Merge misc patches
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmDHZFgACgkQvobrtBUQ T9/QCQ//T8DEv1iekiKPTm1/ZPVCL8IcKDVlmf5bDXBGQ959PHLnWzvocRjn3PfE CSSsHGz9CEwTCqfLG9uO+Ekae/5U8Qk1exe4ykQ+JHBrhyUhvLQ2OC3vl4cNzUwY eh/cQJMUwIbTbw2wPG0kaMmX+Nq+tKohURfFLAT1EJkzb9Z8uWnqjClKjUHpTX56 yUqgHFuba07Ma59/MV4JxImT2u2XIKffdoRq+X57hGU9vyaCMFynmTlCF2+7E3yx Kgz29cPypl40KYL55DTYQ85TM6p2RFyxqEeyycrTq03kXw80mcELAFXh0F6XlsXJ HwubCjvLirp9LqofFf39Z7unvaQ13EbyylBxHZ2gwu6Iw23fDbZjMXWI0jm8nIDv YEUxqYBembNDXHECufzq9ySaWOCBkgbEFFkpSwzRYU+bPyVwyhKg/BN3XVcaqqp+ E9GKApYhQ7maBJJ/puPCih/Ib7LnMAN5GOBJNDaFUxKMGvf9ZfeOkilE+NVAqYn4 fadmhueyGQ4ofZ2c+cmz9sTP9vAfNjDrCOsfTlYKU0zh/WV/QrstZtSsBAqKojWg mXKS1cUx01bRDzaUG2W62SR8/b6ffmDQwPQmfgNpmG2/stSnNG34MJB4vsUbLZvM lBy8izUhK0yvx/wIt4BGxFwHnhCfr4Lu9UGzSqi3etGreHysGYc= =APsS -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/berrange-gitlab/tags/misc-fixes-pull-request' into staging Merge misc patches # gpg: Signature made Mon 14 Jun 2021 15:14:48 BST # gpg: using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [full] # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" [full] # Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E 8E3F BE86 EBB4 1510 4FDF * remotes/berrange-gitlab/tags/misc-fixes-pull-request: usb/dev-mtp: use GDateTime for formatting timestamp for objects block: use GDateTime for formatting timestamp when dumping snapshot info migration: use GDateTime for formatting timestamp in snapshot names block: remove duplicate trace.h include block: add trace point when fdatasync fails block: preserve errno from fdatasync failures softmmu: add trace point when bdrv_flush_all fails migration: add trace point when vm_stop_force_state fails sasl: remove comment about obsolete kerberos versions docs: recommend SCRAM-SHA-256 SASL mech instead of SHA-1 variant docs: document usage of the authorization framework docs: document how to pass secret data to QEMU docs: add table of contents to QAPI references Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
1ea06abcee
|
@ -106,8 +106,6 @@
|
||||||
#include <xfs/xfs.h>
|
#include <xfs/xfs.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "trace.h"
|
|
||||||
|
|
||||||
/* OS X does not have O_DSYNC */
|
/* OS X does not have O_DSYNC */
|
||||||
#ifndef O_DSYNC
|
#ifndef O_DSYNC
|
||||||
#ifdef O_SYNC
|
#ifdef O_SYNC
|
||||||
|
@ -160,7 +158,7 @@ typedef struct BDRVRawState {
|
||||||
bool discard_zeroes:1;
|
bool discard_zeroes:1;
|
||||||
bool use_linux_aio:1;
|
bool use_linux_aio:1;
|
||||||
bool use_linux_io_uring:1;
|
bool use_linux_io_uring:1;
|
||||||
bool page_cache_inconsistent:1;
|
int page_cache_inconsistent; /* errno from fdatasync failure */
|
||||||
bool has_fallocate;
|
bool has_fallocate;
|
||||||
bool needs_alignment;
|
bool needs_alignment;
|
||||||
bool drop_cache;
|
bool drop_cache;
|
||||||
|
@ -1333,11 +1331,13 @@ static int handle_aiocb_flush(void *opaque)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (s->page_cache_inconsistent) {
|
if (s->page_cache_inconsistent) {
|
||||||
return -EIO;
|
return -s->page_cache_inconsistent;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qemu_fdatasync(aiocb->aio_fildes);
|
ret = qemu_fdatasync(aiocb->aio_fildes);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
|
trace_file_flush_fdatasync_failed(errno);
|
||||||
|
|
||||||
/* There is no clear definition of the semantics of a failing fsync(),
|
/* There is no clear definition of the semantics of a failing fsync(),
|
||||||
* so we may have to assume the worst. The sad truth is that this
|
* so we may have to assume the worst. The sad truth is that this
|
||||||
* assumption is correct for Linux. Some pages are now probably marked
|
* assumption is correct for Linux. Some pages are now probably marked
|
||||||
|
@ -1352,7 +1352,7 @@ static int handle_aiocb_flush(void *opaque)
|
||||||
* Obviously, this doesn't affect O_DIRECT, which bypasses the page
|
* Obviously, this doesn't affect O_DIRECT, which bypasses the page
|
||||||
* cache. */
|
* cache. */
|
||||||
if ((s->open_flags & O_DIRECT) == 0) {
|
if ((s->open_flags & O_DIRECT) == 0) {
|
||||||
s->page_cache_inconsistent = true;
|
s->page_cache_inconsistent = errno;
|
||||||
}
|
}
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
11
block/qapi.c
11
block/qapi.c
|
@ -663,10 +663,8 @@ BlockStatsList *qmp_query_blockstats(bool has_query_nodes,
|
||||||
|
|
||||||
void bdrv_snapshot_dump(QEMUSnapshotInfo *sn)
|
void bdrv_snapshot_dump(QEMUSnapshotInfo *sn)
|
||||||
{
|
{
|
||||||
char date_buf[128], clock_buf[128];
|
char clock_buf[128];
|
||||||
char icount_buf[128] = {0};
|
char icount_buf[128] = {0};
|
||||||
struct tm tm;
|
|
||||||
time_t ti;
|
|
||||||
int64_t secs;
|
int64_t secs;
|
||||||
char *sizing = NULL;
|
char *sizing = NULL;
|
||||||
|
|
||||||
|
@ -674,10 +672,9 @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn)
|
||||||
qemu_printf("%-10s%-17s%8s%20s%13s%11s",
|
qemu_printf("%-10s%-17s%8s%20s%13s%11s",
|
||||||
"ID", "TAG", "VM SIZE", "DATE", "VM CLOCK", "ICOUNT");
|
"ID", "TAG", "VM SIZE", "DATE", "VM CLOCK", "ICOUNT");
|
||||||
} else {
|
} else {
|
||||||
ti = sn->date_sec;
|
g_autoptr(GDateTime) date = g_date_time_new_from_unix_local(sn->date_sec);
|
||||||
localtime_r(&ti, &tm);
|
g_autofree char *date_buf = g_date_time_format(date, "%Y-%m-%d %H:%M:%S");
|
||||||
strftime(date_buf, sizeof(date_buf),
|
|
||||||
"%Y-%m-%d %H:%M:%S", &tm);
|
|
||||||
secs = sn->vm_clock_nsec / 1000000000;
|
secs = sn->vm_clock_nsec / 1000000000;
|
||||||
snprintf(clock_buf, sizeof(clock_buf),
|
snprintf(clock_buf, sizeof(clock_buf),
|
||||||
"%02d:%02d:%02d.%03d",
|
"%02d:%02d:%02d.%03d",
|
||||||
|
|
|
@ -206,6 +206,7 @@ file_copy_file_range(void *bs, int src, int64_t src_off, int dst, int64_t dst_of
|
||||||
file_FindEjectableOpticalMedia(const char *media) "Matching using %s"
|
file_FindEjectableOpticalMedia(const char *media) "Matching using %s"
|
||||||
file_setup_cdrom(const char *partition) "Using %s as optical disc"
|
file_setup_cdrom(const char *partition) "Using %s as optical disc"
|
||||||
file_hdev_is_sg(int type, int version) "SG device found: type=%d, version=%d"
|
file_hdev_is_sg(int type, int version) "SG device found: type=%d, version=%d"
|
||||||
|
file_flush_fdatasync_failed(int err) "errno %d"
|
||||||
|
|
||||||
# ssh.c
|
# ssh.c
|
||||||
sftp_error(const char *op, const char *ssh_err, int ssh_err_code, int sftp_err_code) "%s failed: %s (libssh error code: %d, sftp error code: %d)"
|
sftp_error(const char *op, const char *ssh_err, int ssh_err_code, int sftp_err_code) "%s failed: %s (libssh error code: %d, sftp error code: %d)"
|
||||||
|
|
|
@ -10,4 +10,7 @@ QEMU Guest Agent Protocol Reference
|
||||||
TODO: display the QEMU version, both here and in our Sphinx manuals
|
TODO: display the QEMU version, both here and in our Sphinx manuals
|
||||||
more generally.
|
more generally.
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:depth: 3
|
||||||
|
|
||||||
.. qapi-doc:: qga/qapi-schema.json
|
.. qapi-doc:: qga/qapi-schema.json
|
||||||
|
|
|
@ -10,4 +10,7 @@ QEMU QMP Reference Manual
|
||||||
TODO: display the QEMU version, both here and in our Sphinx manuals
|
TODO: display the QEMU version, both here and in our Sphinx manuals
|
||||||
more generally.
|
more generally.
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:depth: 3
|
||||||
|
|
||||||
.. qapi-doc:: qapi/qapi-schema.json
|
.. qapi-doc:: qapi/qapi-schema.json
|
||||||
|
|
|
@ -10,4 +10,7 @@ QEMU Storage Daemon QMP Reference Manual
|
||||||
TODO: display the QEMU version, both here and in our Sphinx manuals
|
TODO: display the QEMU version, both here and in our Sphinx manuals
|
||||||
more generally.
|
more generally.
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:depth: 3
|
||||||
|
|
||||||
.. qapi-doc:: storage-daemon/qapi/qapi-schema.json
|
.. qapi-doc:: storage-daemon/qapi/qapi-schema.json
|
||||||
|
|
|
@ -0,0 +1,263 @@
|
||||||
|
.. _client authorization:
|
||||||
|
|
||||||
|
Client authorization
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
When configuring a QEMU network backend with either TLS certificates or SASL
|
||||||
|
authentication, access will be granted if the client successfully proves
|
||||||
|
their identity. If the authorization identity database is scoped to the QEMU
|
||||||
|
client this may be sufficient. It is common, however, for the identity database
|
||||||
|
to be much broader and thus authentication alone does not enable sufficient
|
||||||
|
access control. In this case QEMU provides a flexible system for enforcing
|
||||||
|
finer grained authorization on clients post-authentication.
|
||||||
|
|
||||||
|
Identity providers
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
At the time of writing there are two authentication frameworks used by QEMU
|
||||||
|
that emit an identity upon completion.
|
||||||
|
|
||||||
|
* TLS x509 certificate distinguished name.
|
||||||
|
|
||||||
|
When configuring the QEMU backend as a network server with TLS, there
|
||||||
|
are a choice of credentials to use. The most common scenario is to utilize
|
||||||
|
x509 certificates. The simplest configuration only involves issuing
|
||||||
|
certificates to the servers, allowing the client to avoid a MITM attack
|
||||||
|
against their intended server.
|
||||||
|
|
||||||
|
It is possible, however, to enable mutual verification by requiring that
|
||||||
|
the client provide a certificate to the server to prove its own identity.
|
||||||
|
This is done by setting the property ``verify-peer=yes`` on the
|
||||||
|
``tls-creds-x509`` object, which is in fact the default.
|
||||||
|
|
||||||
|
When peer verification is enabled, client will need to be issued with a
|
||||||
|
certificate by the same certificate authority as the server. If this is
|
||||||
|
still not sufficiently strong access control the Distinguished Name of
|
||||||
|
the certificate can be used as an identity in the QEMU authorization
|
||||||
|
framework.
|
||||||
|
|
||||||
|
* SASL username.
|
||||||
|
|
||||||
|
When configuring the QEMU backend as a network server with SASL, upon
|
||||||
|
completion of the SASL authentication mechanism, a username will be
|
||||||
|
provided. The format of this username will vary depending on the choice
|
||||||
|
of mechanism configured for SASL. It might be a simple UNIX style user
|
||||||
|
``joebloggs``, while if using Kerberos/GSSAPI it can have a realm
|
||||||
|
attached ``joebloggs@QEMU.ORG``. Whatever format the username is presented
|
||||||
|
in, it can be used with the QEMU authorization framework.
|
||||||
|
|
||||||
|
Authorization drivers
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The QEMU authorization framework is a general purpose design with choice of
|
||||||
|
user customizable drivers. These are provided as objects that can be
|
||||||
|
created at startup using the ``-object`` argument, or at runtime using the
|
||||||
|
``object_add`` monitor command.
|
||||||
|
|
||||||
|
Simple
|
||||||
|
^^^^^^
|
||||||
|
|
||||||
|
This authorization driver provides a simple mechanism for granting access
|
||||||
|
based on an exact match against a single identity. This is useful when it is
|
||||||
|
known that only a single client is to be allowed access.
|
||||||
|
|
||||||
|
A possible use case would be when configuring QEMU for an incoming live
|
||||||
|
migration. It is known exactly which source QEMU the migration is expected
|
||||||
|
to arrive from. The x509 certificate associated with this source QEMU would
|
||||||
|
thus be used as the identity to match against. Alternatively if the virtual
|
||||||
|
machine is dedicated to a specific tenant, then the VNC server would be
|
||||||
|
configured with SASL and the username of only that tenant listed.
|
||||||
|
|
||||||
|
To create an instance of this driver via QMP:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
{
|
||||||
|
"execute": "object-add",
|
||||||
|
"arguments": {
|
||||||
|
"qom-type": "authz-simple",
|
||||||
|
"id": "authz0",
|
||||||
|
"props": {
|
||||||
|
"identity": "fred"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Or via the command line
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-object authz-simple,id=authz0,identity=fred
|
||||||
|
|
||||||
|
|
||||||
|
List
|
||||||
|
^^^^
|
||||||
|
|
||||||
|
In some network backends it will be desirable to grant access to a range of
|
||||||
|
clients. This authorization driver provides a list mechanism for granting
|
||||||
|
access by matching identities against a list of permitted one. Each match
|
||||||
|
rule has an associated policy and a catch all policy applies if no rule
|
||||||
|
matches. The match can either be done as an exact string comparison, or can
|
||||||
|
use the shell-like glob syntax, which allows for use of wildcards.
|
||||||
|
|
||||||
|
To create an instance of this class via QMP:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
{
|
||||||
|
"execute": "object-add",
|
||||||
|
"arguments": {
|
||||||
|
"qom-type": "authz-list",
|
||||||
|
"id": "authz0",
|
||||||
|
"props": {
|
||||||
|
"rules": [
|
||||||
|
{ "match": "fred", "policy": "allow", "format": "exact" },
|
||||||
|
{ "match": "bob", "policy": "allow", "format": "exact" },
|
||||||
|
{ "match": "danb", "policy": "deny", "format": "exact" },
|
||||||
|
{ "match": "dan*", "policy": "allow", "format": "glob" }
|
||||||
|
],
|
||||||
|
"policy": "deny"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Due to the way this driver requires setting nested properties, creating
|
||||||
|
it on the command line will require use of the JSON syntax for ``-object``.
|
||||||
|
In most cases, however, the next driver will be more suitable.
|
||||||
|
|
||||||
|
List file
|
||||||
|
^^^^^^^^^
|
||||||
|
|
||||||
|
This is a variant on the previous driver that allows for a more dynamic
|
||||||
|
access control policy by storing the match rules in a standalone file
|
||||||
|
that can be reloaded automatically upon change.
|
||||||
|
|
||||||
|
To create an instance of this class via QMP:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
{
|
||||||
|
"execute": "object-add",
|
||||||
|
"arguments": {
|
||||||
|
"qom-type": "authz-list-file",
|
||||||
|
"id": "authz0",
|
||||||
|
"props": {
|
||||||
|
"filename": "/etc/qemu/myvm-vnc.acl",
|
||||||
|
"refresh": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
If ``refresh`` is ``yes``, inotify is used to monitor for changes
|
||||||
|
to the file and auto-reload the rules.
|
||||||
|
|
||||||
|
The ``myvm-vnc.acl`` file should contain the match rules in a format that
|
||||||
|
closely matches the previous driver:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
{
|
||||||
|
"rules": [
|
||||||
|
{ "match": "fred", "policy": "allow", "format": "exact" },
|
||||||
|
{ "match": "bob", "policy": "allow", "format": "exact" },
|
||||||
|
{ "match": "danb", "policy": "deny", "format": "exact" },
|
||||||
|
{ "match": "dan*", "policy": "allow", "format": "glob" }
|
||||||
|
],
|
||||||
|
"policy": "deny"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
The object can be created on the command line using
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-object authz-list-file,id=authz0,\
|
||||||
|
filename=/etc/qemu/myvm-vnc.acl,refresh=on
|
||||||
|
|
||||||
|
|
||||||
|
PAM
|
||||||
|
^^^
|
||||||
|
|
||||||
|
In some scenarios it might be desirable to integrate with authorization
|
||||||
|
mechanisms that are implemented outside of QEMU. In order to allow maximum
|
||||||
|
flexibility, QEMU provides a driver that uses the ``PAM`` framework.
|
||||||
|
|
||||||
|
To create an instance of this class via QMP:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
{
|
||||||
|
"execute": "object-add",
|
||||||
|
"arguments": {
|
||||||
|
"qom-type": "authz-pam",
|
||||||
|
"id": "authz0",
|
||||||
|
"parameters": {
|
||||||
|
"service": "qemu-vnc-tls"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
The driver only uses the PAM "account" verification
|
||||||
|
subsystem. The above config would require a config
|
||||||
|
file /etc/pam.d/qemu-vnc-tls. For a simple file
|
||||||
|
lookup it would contain
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
account requisite pam_listfile.so item=user sense=allow \
|
||||||
|
file=/etc/qemu/vnc.allow
|
||||||
|
|
||||||
|
|
||||||
|
The external file would then contain a list of usernames.
|
||||||
|
If x509 cert was being used as the username, a suitable
|
||||||
|
entry would match the distinguished name:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
CN=laptop.berrange.com,O=Berrange Home,L=London,ST=London,C=GB
|
||||||
|
|
||||||
|
|
||||||
|
On the command line it can be created using
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-object authz-pam,id=authz0,service=qemu-vnc-tls
|
||||||
|
|
||||||
|
|
||||||
|
There are a variety of PAM plugins that can be used which are not illustrated
|
||||||
|
here, and it is possible to implement brand new plugins using the PAM API.
|
||||||
|
|
||||||
|
|
||||||
|
Connecting backends
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The authorization driver is created using the ``-object`` argument and then
|
||||||
|
needs to be associated with a network service. The authorization driver object
|
||||||
|
will be given a unique ID that needs to be referenced.
|
||||||
|
|
||||||
|
The property to set in the network service will vary depending on the type of
|
||||||
|
identity to verify. By convention, any network server backend that uses TLS
|
||||||
|
will provide ``tls-authz`` property, while any server using SASL will provide
|
||||||
|
a ``sasl-authz`` property.
|
||||||
|
|
||||||
|
Thus an example using SASL and authorization for the VNC server would look
|
||||||
|
like:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
$QEMU --object authz-simple,id=authz0,identity=fred \
|
||||||
|
--vnc 0.0.0.0:1,sasl,sasl-authz=authz0
|
||||||
|
|
||||||
|
While to validate both the x509 certificate and SASL username:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
echo "CN=laptop.qemu.org,O=QEMU Project,L=London,ST=London,C=GB" >> tls.acl
|
||||||
|
$QEMU --object authz-simple,id=authz0,identity=fred \
|
||||||
|
--object authz-list-file,id=authz1,filename=tls.acl \
|
||||||
|
--object tls-creds-x509,id=tls0,dir=/etc/qemu/tls,verify-peer=yes \
|
||||||
|
--vnc 0.0.0.0:1,sasl,sasl-authz=auth0,tls-creds=tls0,tls-authz=authz1
|
|
@ -30,6 +30,8 @@ Contents:
|
||||||
guest-loader
|
guest-loader
|
||||||
vnc-security
|
vnc-security
|
||||||
tls
|
tls
|
||||||
|
secrets
|
||||||
|
authz
|
||||||
gdb
|
gdb
|
||||||
managed-startup
|
managed-startup
|
||||||
cpu-hotplug
|
cpu-hotplug
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
.. _secret data:
|
||||||
|
|
||||||
|
Providing secret data to QEMU
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
There are a variety of objects in QEMU which require secret data to be provided
|
||||||
|
by the administrator or management application. For example, network block
|
||||||
|
devices often require a password, LUKS block devices require a passphrase to
|
||||||
|
unlock key material, remote desktop services require an access password.
|
||||||
|
QEMU has a general purpose mechanism for providing secret data to QEMU in a
|
||||||
|
secure manner, using the ``secret`` object type.
|
||||||
|
|
||||||
|
At startup this can be done using the ``-object secret,...`` command line
|
||||||
|
argument. At runtime this can be done using the ``object_add`` QMP / HMP
|
||||||
|
monitor commands. The examples that follow will illustrate use of ``-object``
|
||||||
|
command lines, but they all apply equivalentely in QMP / HMP. When creating
|
||||||
|
a ``secret`` object it must be given a unique ID string. This ID is then
|
||||||
|
used to identify the object when configuring the thing which need the data.
|
||||||
|
|
||||||
|
|
||||||
|
INSECURE: Passing secrets as clear text inline
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
**The following should never be done in a production environment or on a
|
||||||
|
multi-user host. Command line arguments are usually visible in the process
|
||||||
|
listings and are often collected in log files by system monitoring agents
|
||||||
|
or bug reporting tools. QMP/HMP commands and their arguments are also often
|
||||||
|
logged and attached to bug reports. This all risks compromising secrets that
|
||||||
|
are passed inline.**
|
||||||
|
|
||||||
|
For the convenience of people debugging / developing with QEMU, it is possible
|
||||||
|
to pass secret data inline on the command line.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-object secret,id=secvnc0,data=87539319
|
||||||
|
|
||||||
|
|
||||||
|
Again it is possible to provide the data in base64 encoded format, which is
|
||||||
|
particularly useful if the data contains binary characters that would clash
|
||||||
|
with argument parsing.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-object secret,id=secvnc0,data=ODc1MzkzMTk=,format=base64
|
||||||
|
|
||||||
|
|
||||||
|
**Note: base64 encoding does not provide any security benefit.**
|
||||||
|
|
||||||
|
Passing secrets as clear text via a file
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The simplest approach to providing data securely is to use a file to store
|
||||||
|
the secret:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-object secret,id=secvnc0,file=vnc-password.txt
|
||||||
|
|
||||||
|
|
||||||
|
In this example the file ``vnc-password.txt`` contains the plain text secret
|
||||||
|
data. It is important to note that the contents of the file are treated as an
|
||||||
|
opaque blob. The entire raw file contents is used as the value, thus it is
|
||||||
|
important not to mistakenly add any trailing newline character in the file if
|
||||||
|
this newline is not intended to be part of the secret data.
|
||||||
|
|
||||||
|
In some cases it might be more convenient to pass the secret data in base64
|
||||||
|
format and have QEMU decode to get the raw bytes before use:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-object secret,id=sec0,file=vnc-password.txt,format=base64
|
||||||
|
|
||||||
|
|
||||||
|
The file should generally be given mode ``0600`` or ``0400`` permissions, and
|
||||||
|
have its user/group ownership set to the same account that the QEMU process
|
||||||
|
will be launched under. If using mandatory access control such as SELinux, then
|
||||||
|
the file should be labelled to only grant access to the specific QEMU process
|
||||||
|
that needs access. This will prevent other processes/users from compromising the
|
||||||
|
secret data.
|
||||||
|
|
||||||
|
|
||||||
|
Passing secrets as cipher text inline
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
To address the insecurity of passing secrets inline as clear text, it is
|
||||||
|
possible to configure a second secret as an AES key to use for decrypting
|
||||||
|
the data.
|
||||||
|
|
||||||
|
The secret used as the AES key must always be configured using the file based
|
||||||
|
storage mechanism:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-object secret,id=secmaster,file=masterkey.data,format=base64
|
||||||
|
|
||||||
|
|
||||||
|
In this case the ``masterkey.data`` file would be initialized with 32
|
||||||
|
cryptographically secure random bytes, which are then base64 encoded.
|
||||||
|
The contents of this file will by used as an AES-256 key to encrypt the
|
||||||
|
real secret that can now be safely passed to QEMU inline as cipher text
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-object secret,id=secvnc0,keyid=secmaster,data=BASE64-CIPHERTEXT,iv=BASE64-IV,format=base64
|
||||||
|
|
||||||
|
|
||||||
|
In this example ``BASE64-CIPHERTEXT`` is the result of AES-256-CBC encrypting
|
||||||
|
the secret with ``masterkey.data`` and then base64 encoding the ciphertext.
|
||||||
|
The ``BASE64-IV`` data is 16 random bytes which have been base64 encrypted.
|
||||||
|
These bytes are used as the initialization vector for the AES-256-CBC value.
|
||||||
|
|
||||||
|
A single master key can be used to encrypt all subsequent secrets, **but it is
|
||||||
|
critical that a different initialization vector is used for every secret**.
|
||||||
|
|
||||||
|
Passing secrets via the Linux keyring
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The earlier mechanisms described are platform agnostic. If using QEMU on a Linux
|
||||||
|
host, it is further possible to pass secrets to QEMU using the Linux keyring:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-object secret_keyring,id=secvnc0,serial=1729
|
||||||
|
|
||||||
|
|
||||||
|
This instructs QEMU to load data from the Linux keyring secret identified by
|
||||||
|
the serial number ``1729``. It is possible to combine use of the keyring with
|
||||||
|
other features mentioned earlier such as base64 encoding:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-object secret_keyring,id=secvnc0,serial=1729,format=base64
|
||||||
|
|
||||||
|
|
||||||
|
and also encryption with a master key:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-object secret_keyring,id=secvnc0,keyid=secmaster,serial=1729,iv=BASE64-IV
|
||||||
|
|
||||||
|
|
||||||
|
Best practice
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
It is recommended for production deployments to use a master key secret, and
|
||||||
|
then pass all subsequent inline secrets encrypted with the master key.
|
||||||
|
|
||||||
|
Each QEMU instance must have a distinct master key, and that must be generated
|
||||||
|
from a cryptographically secure random data source. The master key should be
|
||||||
|
deleted immediately upon QEMU shutdown. If passing the master key as a file,
|
||||||
|
the key file must have access control rules applied that restrict access to
|
||||||
|
just the one QEMU process that is intended to use it. Alternatively the Linux
|
||||||
|
keyring can be used to pass the master key to QEMU.
|
||||||
|
|
||||||
|
The secrets for individual QEMU device backends must all then be encrypted
|
||||||
|
with this master key.
|
||||||
|
|
||||||
|
This procedure helps ensure that the individual secrets for QEMU backends will
|
||||||
|
not be compromised, even if ``-object`` CLI args or ``object_add`` monitor
|
||||||
|
commands are collected in log files and attached to public bug support tickets.
|
||||||
|
The only item that needs strongly protecting is the master key file.
|
|
@ -168,7 +168,7 @@ used is drastically reduced. In fact only the GSSAPI SASL mechanism
|
||||||
provides an acceptable level of security by modern standards. Previous
|
provides an acceptable level of security by modern standards. Previous
|
||||||
versions of QEMU referred to the DIGEST-MD5 mechanism, however, it has
|
versions of QEMU referred to the DIGEST-MD5 mechanism, however, it has
|
||||||
multiple serious flaws described in detail in RFC 6331 and thus should
|
multiple serious flaws described in detail in RFC 6331 and thus should
|
||||||
never be used any more. The SCRAM-SHA-1 mechanism provides a simple
|
never be used any more. The SCRAM-SHA-256 mechanism provides a simple
|
||||||
username/password auth facility similar to DIGEST-MD5, but does not
|
username/password auth facility similar to DIGEST-MD5, but does not
|
||||||
support session encryption, so can only be used in combination with TLS.
|
support session encryption, so can only be used in combination with TLS.
|
||||||
|
|
||||||
|
@ -191,11 +191,12 @@ reasonable configuration is
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
mech_list: scram-sha-1
|
mech_list: scram-sha-256
|
||||||
sasldb_path: /etc/qemu/passwd.db
|
sasldb_path: /etc/qemu/passwd.db
|
||||||
|
|
||||||
The ``saslpasswd2`` program can be used to populate the ``passwd.db``
|
The ``saslpasswd2`` program can be used to populate the ``passwd.db``
|
||||||
file with accounts.
|
file with accounts. Note that the ``passwd.db`` file stores passwords
|
||||||
|
in clear text.
|
||||||
|
|
||||||
Other SASL configurations will be left as an exercise for the reader.
|
Other SASL configurations will be left as an exercise for the reader.
|
||||||
Note that all mechanisms, except GSSAPI, should be combined with use of
|
Note that all mechanisms, except GSSAPI, should be combined with use of
|
||||||
|
|
|
@ -772,12 +772,9 @@ static void usb_mtp_add_str(MTPData *data, const char *str)
|
||||||
|
|
||||||
static void usb_mtp_add_time(MTPData *data, time_t time)
|
static void usb_mtp_add_time(MTPData *data, time_t time)
|
||||||
{
|
{
|
||||||
char buf[16];
|
g_autoptr(GDateTime) then = g_date_time_new_from_unix_utc(time);
|
||||||
struct tm tm;
|
g_autofree char *thenstr = g_date_time_format(then, "%Y%m%dT%H%M%S");
|
||||||
|
usb_mtp_add_str(data, thenstr);
|
||||||
gmtime_r(&time, &tm);
|
|
||||||
strftime(buf, sizeof(buf), "%Y%m%dT%H%M%S", &tm);
|
|
||||||
usb_mtp_add_str(data, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
|
|
|
@ -3115,6 +3115,7 @@ static void migration_completion(MigrationState *s)
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
bool inactivate = !migrate_colo_enabled();
|
bool inactivate = !migrate_colo_enabled();
|
||||||
ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
|
ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
|
||||||
|
trace_migration_completion_vm_stop(ret);
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
ret = migration_maybe_pause(s, ¤t_active_state,
|
ret = migration_maybe_pause(s, ¤t_active_state,
|
||||||
MIGRATION_STATUS_DEVICE);
|
MIGRATION_STATUS_DEVICE);
|
||||||
|
|
|
@ -2775,8 +2775,7 @@ bool save_snapshot(const char *name, bool overwrite, const char *vmstate,
|
||||||
QEMUFile *f;
|
QEMUFile *f;
|
||||||
int saved_vm_running;
|
int saved_vm_running;
|
||||||
uint64_t vm_state_size;
|
uint64_t vm_state_size;
|
||||||
qemu_timeval tv;
|
g_autoptr(GDateTime) now = g_date_time_new_now_local();
|
||||||
struct tm tm;
|
|
||||||
AioContext *aio_context;
|
AioContext *aio_context;
|
||||||
|
|
||||||
if (migration_is_blocked(errp)) {
|
if (migration_is_blocked(errp)) {
|
||||||
|
@ -2836,9 +2835,8 @@ bool save_snapshot(const char *name, bool overwrite, const char *vmstate,
|
||||||
memset(sn, 0, sizeof(*sn));
|
memset(sn, 0, sizeof(*sn));
|
||||||
|
|
||||||
/* fill auxiliary fields */
|
/* fill auxiliary fields */
|
||||||
qemu_gettimeofday(&tv);
|
sn->date_sec = g_date_time_to_unix(now);
|
||||||
sn->date_sec = tv.tv_sec;
|
sn->date_nsec = g_date_time_get_microsecond(now) * 1000;
|
||||||
sn->date_nsec = tv.tv_usec * 1000;
|
|
||||||
sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
if (replay_mode != REPLAY_MODE_NONE) {
|
if (replay_mode != REPLAY_MODE_NONE) {
|
||||||
sn->icount = replay_get_current_icount();
|
sn->icount = replay_get_current_icount();
|
||||||
|
@ -2849,9 +2847,8 @@ bool save_snapshot(const char *name, bool overwrite, const char *vmstate,
|
||||||
if (name) {
|
if (name) {
|
||||||
pstrcpy(sn->name, sizeof(sn->name), name);
|
pstrcpy(sn->name, sizeof(sn->name), name);
|
||||||
} else {
|
} else {
|
||||||
/* cast below needed for OpenBSD where tv_sec is still 'long' */
|
g_autofree char *autoname = g_date_time_format(now, "vm-%Y%m%d%H%M%S");
|
||||||
localtime_r((const time_t *)&tv.tv_sec, &tm);
|
pstrcpy(sn->name, sizeof(sn->name), autoname);
|
||||||
strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", &tm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* save the VM state */
|
/* save the VM state */
|
||||||
|
|
|
@ -149,6 +149,7 @@ migrate_pending(uint64_t size, uint64_t max, uint64_t pre, uint64_t compat, uint
|
||||||
migrate_send_rp_message(int msg_type, uint16_t len) "%d: len %d"
|
migrate_send_rp_message(int msg_type, uint16_t len) "%d: len %d"
|
||||||
migrate_send_rp_recv_bitmap(char *name, int64_t size) "block '%s' size 0x%"PRIi64
|
migrate_send_rp_recv_bitmap(char *name, int64_t size) "block '%s' size 0x%"PRIi64
|
||||||
migration_completion_file_err(void) ""
|
migration_completion_file_err(void) ""
|
||||||
|
migration_completion_vm_stop(int ret) "ret %d"
|
||||||
migration_completion_postcopy_end(void) ""
|
migration_completion_postcopy_end(void) ""
|
||||||
migration_completion_postcopy_end_after_complete(void) ""
|
migration_completion_postcopy_end_after_complete(void) ""
|
||||||
migration_rate_limit_pre(int ms) "%d ms"
|
migration_rate_limit_pre(int ms) "%d ms"
|
||||||
|
|
15
qemu.sasl
15
qemu.sasl
|
@ -19,26 +19,23 @@ mech_list: gssapi
|
||||||
|
|
||||||
# If using TLS with VNC, or a UNIX socket only, it is possible to
|
# If using TLS with VNC, or a UNIX socket only, it is possible to
|
||||||
# enable plugins which don't provide session encryption. The
|
# enable plugins which don't provide session encryption. The
|
||||||
# 'scram-sha-1' plugin allows plain username/password authentication
|
# 'scram-sha-256' plugin allows plain username/password authentication
|
||||||
# to be performed
|
# to be performed
|
||||||
#
|
#
|
||||||
#mech_list: scram-sha-1
|
#mech_list: scram-sha-256
|
||||||
|
|
||||||
# You can also list many mechanisms at once, and the VNC server will
|
# You can also list many mechanisms at once, and the VNC server will
|
||||||
# negotiate which to use by considering the list enabled on the VNC
|
# negotiate which to use by considering the list enabled on the VNC
|
||||||
# client.
|
# client.
|
||||||
#mech_list: scram-sha-1 gssapi
|
#mech_list: scram-sha-256 gssapi
|
||||||
|
|
||||||
# Some older builds of MIT kerberos on Linux ignore this option &
|
|
||||||
# instead need KRB5_KTNAME env var.
|
|
||||||
# For modern Linux, and other OS, this should be sufficient
|
|
||||||
#
|
|
||||||
# This file needs to be populated with the service principal that
|
# This file needs to be populated with the service principal that
|
||||||
# was created on the Kerberos v5 server. If switching to a non-gssapi
|
# was created on the Kerberos v5 server. If switching to a non-gssapi
|
||||||
# mechanism this can be commented out.
|
# mechanism this can be commented out.
|
||||||
keytab: /etc/qemu/krb5.tab
|
keytab: /etc/qemu/krb5.tab
|
||||||
|
|
||||||
# If using scram-sha-1 for username/passwds, then this is the file
|
# If using scram-sha-256 for username/passwds, then this is the file
|
||||||
# containing the passwds. Use 'saslpasswd2 -a qemu [username]'
|
# containing the passwds. Use 'saslpasswd2 -a qemu [username]'
|
||||||
# to add entries, and 'sasldblistusers2 -f [sasldb_path]' to browse it
|
# to add entries, and 'sasldblistusers2 -f [sasldb_path]' to browse it.
|
||||||
|
# Note that this file stores passwords in clear text.
|
||||||
#sasldb_path: /etc/qemu/passwd.db
|
#sasldb_path: /etc/qemu/passwd.db
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "sysemu/whpx.h"
|
#include "sysemu/whpx.h"
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
#include "hw/hw.h"
|
#include "hw/hw.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
#ifdef CONFIG_LINUX
|
#ifdef CONFIG_LINUX
|
||||||
|
|
||||||
|
@ -266,6 +267,7 @@ static int do_vm_stop(RunState state, bool send_stop)
|
||||||
|
|
||||||
bdrv_drain_all();
|
bdrv_drain_all();
|
||||||
ret = bdrv_flush_all();
|
ret = bdrv_flush_all();
|
||||||
|
trace_vm_stop_flush_all(ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -704,12 +706,15 @@ int vm_stop_force_state(RunState state)
|
||||||
if (runstate_is_running()) {
|
if (runstate_is_running()) {
|
||||||
return vm_stop(state);
|
return vm_stop(state);
|
||||||
} else {
|
} else {
|
||||||
|
int ret;
|
||||||
runstate_set(state);
|
runstate_set(state);
|
||||||
|
|
||||||
bdrv_drain_all();
|
bdrv_drain_all();
|
||||||
/* Make sure to return an error if the flush in a previous vm_stop()
|
/* Make sure to return an error if the flush in a previous vm_stop()
|
||||||
* failed. */
|
* failed. */
|
||||||
return bdrv_flush_all();
|
ret = bdrv_flush_all();
|
||||||
|
trace_vm_stop_flush_all(ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,9 @@ flatview_new(void *view, void *root) "%p (root %p)"
|
||||||
flatview_destroy(void *view, void *root) "%p (root %p)"
|
flatview_destroy(void *view, void *root) "%p (root %p)"
|
||||||
flatview_destroy_rcu(void *view, void *root) "%p (root %p)"
|
flatview_destroy_rcu(void *view, void *root) "%p (root %p)"
|
||||||
|
|
||||||
|
# softmmu.c
|
||||||
|
vm_stop_flush_all(int ret) "ret %d"
|
||||||
|
|
||||||
# vl.c
|
# vl.c
|
||||||
vm_state_notify(int running, int reason, const char *reason_str) "running %d reason %d (%s)"
|
vm_state_notify(int running, int reason, const char *reason_str) "running %d reason %d (%s)"
|
||||||
load_file(const char *name, const char *path) "name %s location %s"
|
load_file(const char *name, const char *path) "name %s location %s"
|
||||||
|
|
Loading…
Reference in New Issue