qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v3 25/27] migration: add support for encrypting


From: Dr. David Alan Gilbert
Subject: Re: [Qemu-devel] [PATCH v3 25/27] migration: add support for encrypting data with TLS
Date: Thu, 10 Mar 2016 18:25:34 +0000
User-agent: Mutt/1.5.24 (2015-08-30)

* Daniel P. Berrange (address@hidden) wrote:
> This extends the migration_set_incoming_channel and
> migration_set_outgoing_channel methods so that they
> will automatically wrap the QIOChannel in a
> QIOChannelTLS instance if TLS credentials are configured
> in the migration parameters.

Reviewed-by: Dr. David Alan Gilbert <address@hidden>

You might like to check how it behaves with a migrate_cancel
after connect but before the handshake has finished.

I think it will probably work - the cancel does a shutdown()
call so it'll probably cause it to nuke the underlying conenction
that will then cause the handshake callback.

Dave

> This allows TLS to work for tcp, unix, fd and exec
> migration protocols. It does not (currently) work for
> RDMA since it does not use these APIs, but it is
> unlikely that TLS would be desired with RDMA anyway
> since it would degrade the performance to that seen
> with TCP defeating the purpose of using RDMA.
> 
> On the target host, QEMU would be launched with a set
> of TLS credentials for a server endpoint
> 
>  $ qemu-system-x86_64 -monitor stdio -incoming defer \
>     -object 
> tls-creds-x509,dir=/home/berrange/security/qemutls,endpoint=server,id=tls0 \
>     ...other args...
> 
> To enable incoming TLS migration 2 monitor commands are
> then used
> 
>   (qemu) migrate_set_str_parameter tls-creds tls0
>   (qemu) migrate_incoming tcp:myhostname:9000
> 
> On the source host, QEMU is launched in a similar
> manner but using client endpoint credentials
> 
>  $ qemu-system-x86_64 -monitor stdio \
>     -object 
> tls-creds-x509,dir=/home/berrange/security/qemutls,endpoint=client,id=tls0 \
>     ...other args...
> 
> To enable outgoing TLS migration 2 monitor commands are
> then used
> 
>   (qemu) migrate_set_str_parameter tls-creds tls0
>   (qemu) migrate tcp:otherhostname:9000
> 
> Thanks to earlier improvements to error reporting,
> TLS errors can be seen 'info migrate' when doing a
> detached migration. For example:
> 
>   (qemu) info migrate
>   capabilities: xbzrle: off rdma-pin-all: off auto-converge: off zero-blocks: 
> off compress: off events: off x-postcopy-ram: off
>   Migration status: failed
>   total time: 0 milliseconds
>   error description: TLS handshake failed: The TLS connection was 
> non-properly terminated.
> 
> Or
> 
>   (qemu) info migrate
>   capabilities: xbzrle: off rdma-pin-all: off auto-converge: off zero-blocks: 
> off compress: off events: off x-postcopy-ram: off
>   Migration status: failed
>   total time: 0 milliseconds
>   error description: Certificate does not match the hostname localhost
> 
> Signed-off-by: Daniel P. Berrange <address@hidden>
> ---
>  include/migration/migration.h |  12 +++-
>  migration/Makefile.objs       |   1 +
>  migration/exec.c              |   2 +-
>  migration/fd.c                |   2 +-
>  migration/migration.c         |  40 +++++++++--
>  migration/socket.c            |  34 +++++++--
>  migration/tls.c               | 160 
> ++++++++++++++++++++++++++++++++++++++++++
>  trace-events                  |  12 +++-
>  8 files changed, 246 insertions(+), 17 deletions(-)
>  create mode 100644 migration/tls.c
> 
> diff --git a/include/migration/migration.h b/include/migration/migration.h
> index 999a5ee..6310ff4 100644
> --- a/include/migration/migration.h
> +++ b/include/migration/migration.h
> @@ -186,8 +186,18 @@ void qemu_start_incoming_migration(const char *uri, 
> Error **errp);
>  void migration_set_incoming_channel(MigrationState *s,
>                                      QIOChannel *ioc);
>  
> +void migration_tls_set_incoming_channel(MigrationState *s,
> +                                        QIOChannel *ioc,
> +                                        Error **errp);
> +
>  void migration_set_outgoing_channel(MigrationState *s,
> -                                    QIOChannel *ioc);
> +                                    QIOChannel *ioc,
> +                                    const char *hostname);
> +
> +void migration_tls_set_outgoing_channel(MigrationState *s,
> +                                        QIOChannel *ioc,
> +                                        const char *hostname,
> +                                        Error **errp);
>  
>  uint64_t migrate_max_downtime(void);
>  
> diff --git a/migration/Makefile.objs b/migration/Makefile.objs
> index 7b9051c..e68b54d 100644
> --- a/migration/Makefile.objs
> +++ b/migration/Makefile.objs
> @@ -1,4 +1,5 @@
>  common-obj-y += migration.o socket.o fd.o exec.o
> +common-obj-y += tls.o
>  common-obj-y += vmstate.o
>  common-obj-y += qemu-file.o
>  common-obj-y += qemu-file-channel.o
> diff --git a/migration/exec.c b/migration/exec.c
> index 4f439b4..a5debc6 100644
> --- a/migration/exec.c
> +++ b/migration/exec.c
> @@ -36,7 +36,7 @@ void exec_start_outgoing_migration(MigrationState *s, const 
> char *command, Error
>          return;
>      }
>  
> -    migration_set_outgoing_channel(s, ioc);
> +    migration_set_outgoing_channel(s, ioc, NULL);
>      object_unref(OBJECT(ioc));
>  }
>  
> diff --git a/migration/fd.c b/migration/fd.c
> index 1a7fd43..e089bf4 100644
> --- a/migration/fd.c
> +++ b/migration/fd.c
> @@ -36,7 +36,7 @@ void fd_start_outgoing_migration(MigrationState *s, const 
> char *fdname, Error **
>          return;
>      }
>  
> -    migration_set_outgoing_channel(s, ioc);
> +    migration_set_outgoing_channel(s, ioc, NULL);
>      object_unref(OBJECT(ioc));
>  }
>  
> diff --git a/migration/migration.c b/migration/migration.c
> index c7bc1c7..84393c0 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -35,6 +35,7 @@
>  #include "exec/memory.h"
>  #include "exec/address-spaces.h"
>  #include "io/channel-buffer.h"
> +#include "io/channel-tls.h"
>  
>  #define MAX_THROTTLE  (32 << 20)      /* Migration transfer speed throttling 
> */
>  
> @@ -420,20 +421,47 @@ void process_incoming_migration(QEMUFile *f)
>  void migration_set_incoming_channel(MigrationState *s,
>                                      QIOChannel *ioc)
>  {
> -    QEMUFile *f = qemu_fopen_channel_input(ioc);
> +    trace_migration_set_incoming_channel(
> +        ioc, object_get_typename(OBJECT(ioc)));
>  
> -    process_incoming_migration(f);
> +    if (s->parameters.tls_creds &&
> +        !object_dynamic_cast(OBJECT(ioc),
> +                             TYPE_QIO_CHANNEL_TLS)) {
> +        Error *local_err = NULL;
> +        migration_tls_set_incoming_channel(s, ioc, &local_err);
> +        if (local_err) {
> +            error_report_err(local_err);
> +        }
> +    } else {
> +        QEMUFile *f = qemu_fopen_channel_input(ioc);
> +        process_incoming_migration(f);
> +    }
>  }
>  
>  
>  void migration_set_outgoing_channel(MigrationState *s,
> -                                    QIOChannel *ioc)
> +                                    QIOChannel *ioc,
> +                                    const char *hostname)
>  {
> -    QEMUFile *f = qemu_fopen_channel_output(ioc);
> +    trace_migration_set_outgoing_channel(
> +        ioc, object_get_typename(OBJECT(ioc)), hostname);
>  
> -    s->to_dst_file = f;
> +    if (s->parameters.tls_creds &&
> +        !object_dynamic_cast(OBJECT(ioc),
> +                             TYPE_QIO_CHANNEL_TLS)) {
> +        Error *local_err = NULL;
> +        migration_tls_set_outgoing_channel(s, ioc, hostname, &local_err);
> +        if (local_err) {
> +            migrate_fd_error(s, local_err);
> +            error_free(local_err);
> +        }
> +    } else {
> +        QEMUFile *f = qemu_fopen_channel_output(ioc);
>  
> -    migrate_fd_connect(s);
> +        s->to_dst_file = f;
> +
> +        migrate_fd_connect(s);
> +    }
>  }
>  
>  
> diff --git a/migration/socket.c b/migration/socket.c
> index 7e0d9ee..5670f70 100644
> --- a/migration/socket.c
> +++ b/migration/socket.c
> @@ -54,20 +54,35 @@ static SocketAddress *unix_build_address(const char *path)
>  }
>  
>  
> +struct SocketConnectData {
> +    MigrationState *s;
> +    char *hostname;
> +};
> +
> +static void socket_connect_data_free(void *opaque)
> +{
> +    struct SocketConnectData *data = opaque;
> +    if (!data) {
> +        return;
> +    }
> +    g_free(data->hostname);
> +    g_free(data);
> +}
> +
>  static void socket_outgoing_migration(Object *src,
>                                        Error *err,
>                                        gpointer opaque)
>  {
> -    MigrationState *s = opaque;
> +    struct SocketConnectData *data = opaque;
>      QIOChannel *sioc = QIO_CHANNEL(src);
>  
>      if (err) {
>          trace_migration_socket_outgoing_error(error_get_pretty(err));
> -        s->to_dst_file = NULL;
> -        migrate_fd_error(s, err);
> +        data->s->to_dst_file = NULL;
> +        migrate_fd_error(data->s, err);
>      } else {
> -        trace_migration_socket_outgoing_connected();
> -        migration_set_outgoing_channel(s, sioc);
> +        trace_migration_socket_outgoing_connected(data->hostname);
> +        migration_set_outgoing_channel(data->s, sioc, data->hostname);
>      }
>      object_unref(src);
>  }
> @@ -77,11 +92,16 @@ static void 
> socket_start_outgoing_migration(MigrationState *s,
>                                              Error **errp)
>  {
>      QIOChannelSocket *sioc = qio_channel_socket_new();
> +    struct SocketConnectData *data = g_new0(struct SocketConnectData, 1);
> +    data->s = s;
> +    if (saddr->type == SOCKET_ADDRESS_KIND_INET) {
> +        data->hostname = g_strdup(saddr->u.inet->host);
> +    }
>      qio_channel_socket_connect_async(sioc,
>                                       saddr,
>                                       socket_outgoing_migration,
> -                                     s,
> -                                     NULL);
> +                                     data,
> +                                     socket_connect_data_free);
>      qapi_free_SocketAddress(saddr);
>  }
>  
> diff --git a/migration/tls.c b/migration/tls.c
> new file mode 100644
> index 0000000..12a20d6
> --- /dev/null
> +++ b/migration/tls.c
> @@ -0,0 +1,160 @@
> +/*
> + * QEMU migration TLS support
> + *
> + * Copyright (c) 2015 Red Hat, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see 
> <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "migration/migration.h"
> +#include "io/channel-tls.h"
> +#include "crypto/tlscreds.h"
> +#include "qemu/error-report.h"
> +#include "trace.h"
> +
> +static QCryptoTLSCreds *
> +migration_tls_get_creds(MigrationState *s,
> +                        QCryptoTLSCredsEndpoint endpoint,
> +                        Error **errp)
> +{
> +    Object *creds;
> +    QCryptoTLSCreds *ret;
> +
> +    creds = object_resolve_path_component(
> +        object_get_objects_root(), s->parameters.tls_creds);
> +    if (!creds) {
> +        error_setg(errp, "No TLS credentials with id '%s'",
> +                   s->parameters.tls_creds);
> +        return NULL;
> +    }
> +    ret = (QCryptoTLSCreds *)object_dynamic_cast(
> +        creds, TYPE_QCRYPTO_TLS_CREDS);
> +    if (!ret) {
> +        error_setg(errp, "Object with id '%s' is not TLS credentials",
> +                   s->parameters.tls_creds);
> +        return NULL;
> +    }
> +    if (ret->endpoint != endpoint) {
> +        error_setg(errp,
> +                   "Expected TLS credentials for a %s endpoint",
> +                   endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT ?
> +                   "client" : "server");
> +        return NULL;
> +    }
> +
> +    object_ref(OBJECT(ret));
> +    return ret;
> +}
> +
> +
> +static void migration_tls_incoming_handshake(Object *src,
> +                                             Error *err,
> +                                             gpointer opaque)
> +{
> +    QIOChannel *ioc = QIO_CHANNEL(src);
> +
> +    if (err) {
> +        trace_migration_tls_incoming_handshake_error(error_get_pretty(err));
> +        error_report("%s", error_get_pretty(err));
> +    } else {
> +        trace_migration_tls_incoming_handshake_complete();
> +        migration_set_incoming_channel(migrate_get_current(), ioc);
> +    }
> +    object_unref(OBJECT(ioc));
> +}
> +
> +void migration_tls_set_incoming_channel(MigrationState *s,
> +                                        QIOChannel *ioc,
> +                                        Error **errp)
> +{
> +    QCryptoTLSCreds *creds;
> +    QIOChannelTLS *tioc;
> +
> +    creds = migration_tls_get_creds(
> +        s, QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, errp);
> +    if (!creds) {
> +        return;
> +    }
> +
> +    tioc = qio_channel_tls_new_server(
> +        ioc, creds,
> +        NULL, /* XXX pass ACL name */
> +        errp);
> +    if (!tioc) {
> +        return;
> +    }
> +
> +    trace_migration_tls_incoming_handshake_start();
> +    qio_channel_tls_handshake(tioc,
> +                              migration_tls_incoming_handshake,
> +                              NULL,
> +                              NULL);
> +}
> +
> +
> +static void migration_tls_outgoing_handshake(Object *src,
> +                                             Error *err,
> +                                             gpointer opaque)
> +{
> +    MigrationState *s = opaque;
> +    QIOChannel *ioc = QIO_CHANNEL(src);
> +
> +    if (err) {
> +        trace_migration_tls_outgoing_handshake_error(error_get_pretty(err));
> +        s->to_dst_file = NULL;
> +        migrate_fd_error(s, err);
> +    } else {
> +        trace_migration_tls_outgoing_handshake_complete();
> +        migration_set_outgoing_channel(s, ioc, NULL);
> +    }
> +    object_unref(OBJECT(ioc));
> +}
> +
> +
> +void migration_tls_set_outgoing_channel(MigrationState *s,
> +                                        QIOChannel *ioc,
> +                                        const char *hostname,
> +                                        Error **errp)
> +{
> +    QCryptoTLSCreds *creds;
> +    QIOChannelTLS *tioc;
> +
> +    creds = migration_tls_get_creds(
> +        s, QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, errp);
> +    if (!creds) {
> +        return;
> +    }
> +
> +    if (s->parameters.tls_hostname) {
> +        hostname = s->parameters.tls_hostname;
> +    }
> +    if (!hostname) {
> +        error_setg(errp, "No hostname available for TLS");
> +        return;
> +    }
> +
> +    tioc = qio_channel_tls_new_client(
> +        ioc, creds, hostname, errp);
> +    if (!tioc) {
> +        return;
> +    }
> +
> +    trace_migration_tls_outgoing_handshake_start(hostname);
> +    qio_channel_tls_handshake(tioc,
> +                              migration_tls_outgoing_handshake,
> +                              s,
> +                              NULL);
> +}
> diff --git a/trace-events b/trace-events
> index 5b8da12..1dd2066 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -1516,6 +1516,8 @@ migrate_state_too_big(void) ""
>  migrate_transferred(uint64_t tranferred, uint64_t time_spent, double 
> bandwidth, uint64_t size) "transferred %" PRIu64 " time_spent %" PRIu64 " 
> bandwidth %g max_size %" PRId64
>  process_incoming_migration_co_end(int ret, int ps) "ret=%d postcopy-state=%d"
>  process_incoming_migration_co_postcopy_end_main(void) ""
> +migration_set_incoming_channel(void *ioc, const char *ioctype) "ioc=%p 
> ioctype=%s"
> +migration_set_outgoing_channel(void *ioc, const char *ioctype, const char 
> *hostname)  "ioc=%p ioctype=%s hostname=%s"
>  
>  # migration/rdma.c
>  qemu_rdma_accept_incoming_migration(void) ""
> @@ -1610,9 +1612,17 @@ migration_fd_incoming(int fd) "fd=%d"
>  
>  # migration/socket.c
>  migration_socket_incoming_accepted(void) ""
> -migration_socket_outgoing_connected(void) ""
> +migration_socket_outgoing_connected(const char *hostname) "hostname=%s"
>  migration_socket_outgoing_error(const char *err) "error=%s"
>  
> +# migration/tls.c
> +migration_tls_outgoing_handshake_start(const char *hostname) "hostname=%s"
> +migration_tls_outgoing_handshake_error(const char *err) "err=%s"
> +migration_tls_outgoing_handshake_complete(void) ""
> +migration_tls_incoming_handshake_start(void) ""
> +migration_tls_incoming_handshake_error(const char *err) "err=%s"
> +migration_tls_incoming_handshake_complete(void) ""
> +
>  # kvm-all.c
>  kvm_ioctl(int type, void *arg) "type 0x%x, arg %p"
>  kvm_vm_ioctl(int type, void *arg) "type 0x%x, arg %p"
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / address@hidden / Manchester, UK



reply via email to

[Prev in Thread] Current Thread [Next in Thread]