diff --git a/SOURCES/io-remove-io-watch-if-TLS-channel-is-closed.patch b/SOURCES/io-remove-io-watch-if-TLS-channel-is-closed.patch new file mode 100644 index 0000000..345ed05 --- /dev/null +++ b/SOURCES/io-remove-io-watch-if-TLS-channel-is-closed.patch @@ -0,0 +1,80 @@ +From 10be627d2b5ec2d6b3dce045144aa739eef678b4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Tue, 20 Jun 2023 09:45:34 +0100 +Subject: [PATCH] io: remove io watch if TLS channel is closed during handshake +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The TLS handshake make take some time to complete, during which time an +I/O watch might be registered with the main loop. If the owner of the +I/O channel invokes qio_channel_close() while the handshake is waiting +to continue the I/O watch must be removed. Failing to remove it will +later trigger the completion callback which the owner is not expecting +to receive. In the case of the VNC server, this results in a SEGV as +vnc_disconnect_start() tries to shutdown a client connection that is +already gone / NULL. + +CVE-2023-3354 +Reported-by: jiangyegen +Signed-off-by: Daniel P. Berrangé +--- + include/io/channel-tls.h | 1 + + io/channel-tls.c | 18 ++++++++++++------ + 2 files changed, 13 insertions(+), 6 deletions(-) + +diff --git a/include/io/channel-tls.h b/include/io/channel-tls.h +index 5672479e9eb6..26c67f17e2d3 100644 +--- a/include/io/channel-tls.h ++++ b/include/io/channel-tls.h +@@ -48,6 +48,7 @@ struct QIOChannelTLS { + QIOChannel *master; + QCryptoTLSSession *session; + QIOChannelShutdown shutdown; ++ guint hs_ioc_tag; + }; + + /** +diff --git a/io/channel-tls.c b/io/channel-tls.c +index 9805dd0a3f64..847d5297c339 100644 +--- a/io/channel-tls.c ++++ b/io/channel-tls.c +@@ -198,12 +198,13 @@ static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc, + } + + trace_qio_channel_tls_handshake_pending(ioc, status); +- qio_channel_add_watch_full(ioc->master, +- condition, +- qio_channel_tls_handshake_io, +- data, +- NULL, +- context); ++ ioc->hs_ioc_tag = ++ qio_channel_add_watch_full(ioc->master, ++ condition, ++ qio_channel_tls_handshake_io, ++ data, ++ NULL, ++ context); + } + } + +@@ -218,6 +219,7 @@ static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc, + QIOChannelTLS *tioc = QIO_CHANNEL_TLS( + qio_task_get_source(task)); + ++ tioc->hs_ioc_tag = 0; + g_free(data); + qio_channel_tls_handshake_task(tioc, task, context); + +@@ -378,6 +380,10 @@ static int qio_channel_tls_close(QIOChannel *ioc, + { + QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc); + ++ if (tioc->hs_ioc_tag) { ++ g_clear_handle_id(&tioc->hs_ioc_tag, g_source_remove); ++ } ++ + return qio_channel_close(tioc->master, errp); + } + diff --git a/SOURCES/migration-Add-migration-prefix-to-functions-in-target.patch b/SOURCES/migration-Add-migration-prefix-to-functions-in-target.patch new file mode 100644 index 0000000..c65d9e8 --- /dev/null +++ b/SOURCES/migration-Add-migration-prefix-to-functions-in-target.patch @@ -0,0 +1,113 @@ +From 38c482b4778595ee337761f73ec0730d6c47b404 Mon Sep 17 00:00:00 2001 +From: Avihai Horon +Date: Wed, 6 Sep 2023 18:08:48 +0300 +Subject: [PATCH] migration: Add migration prefix to functions in target.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The functions in target.c are not static, yet they don't have a proper +migration prefix. Add such prefix. + +Signed-off-by: Avihai Horon +Reviewed-by: Cédric Le Goater +Signed-off-by: Cédric Le Goater +--- + migration/migration.c | 6 +++--- + migration/migration.h | 4 ++-- + migration/savevm.c | 2 +- + migration/target.c | 8 ++++---- + 4 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/migration/migration.c b/migration/migration.c +index 5528acb65e0f..92866a8f49d3 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -1021,7 +1021,7 @@ static void fill_source_migration_info(MigrationInfo *info) + populate_time_info(info, s); + populate_ram_info(info, s); + populate_disk_info(info); +- populate_vfio_info(info); ++ migration_populate_vfio_info(info); + break; + case MIGRATION_STATUS_COLO: + info->has_status = true; +@@ -1030,7 +1030,7 @@ static void fill_source_migration_info(MigrationInfo *info) + case MIGRATION_STATUS_COMPLETED: + populate_time_info(info, s); + populate_ram_info(info, s); +- populate_vfio_info(info); ++ migration_populate_vfio_info(info); + break; + case MIGRATION_STATUS_FAILED: + info->has_status = true; +@@ -1638,7 +1638,7 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc, + */ + memset(&ram_counters, 0, sizeof(ram_counters)); + memset(&compression_counters, 0, sizeof(compression_counters)); +- reset_vfio_bytes_transferred(); ++ migration_reset_vfio_bytes_transferred(); + + return true; + } +diff --git a/migration/migration.h b/migration/migration.h +index 6eea18db3675..c5695de21496 100644 +--- a/migration/migration.h ++++ b/migration/migration.h +@@ -505,8 +505,8 @@ void migration_consume_urgent_request(void); + bool migration_rate_limit(void); + void migration_cancel(const Error *error); + +-void populate_vfio_info(MigrationInfo *info); +-void reset_vfio_bytes_transferred(void); ++void migration_populate_vfio_info(MigrationInfo *info); ++void migration_reset_vfio_bytes_transferred(void); + void postcopy_temp_page_reset(PostcopyTmpPage *tmp_page); + + #endif +diff --git a/migration/savevm.c b/migration/savevm.c +index 83088fc3f8..05db79bfad 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -1620,7 +1620,7 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp) + migrate_init(ms); + memset(&ram_counters, 0, sizeof(ram_counters)); + memset(&compression_counters, 0, sizeof(compression_counters)); +- reset_vfio_bytes_transferred(); ++ migration_reset_vfio_bytes_transferred(); + ms->to_dst_file = f; + + qemu_mutex_unlock_iothread(); +diff --git a/migration/target.c b/migration/target.c +index f39c9a8d8877..a6ffa9a5ce31 100644 +--- a/migration/target.c ++++ b/migration/target.c +@@ -15,7 +15,7 @@ + #endif + + #ifdef CONFIG_VFIO +-void populate_vfio_info(MigrationInfo *info) ++void migration_populate_vfio_info(MigrationInfo *info) + { + if (vfio_mig_active()) { + info->vfio = g_malloc0(sizeof(*info->vfio)); +@@ -23,16 +23,16 @@ void populate_vfio_info(MigrationInfo *info) + } + } + +-void reset_vfio_bytes_transferred(void) ++void migration_reset_vfio_bytes_transferred(void) + { + vfio_reset_bytes_transferred(); + } + #else +-void populate_vfio_info(MigrationInfo *info) ++void migration_populate_vfio_info(MigrationInfo *info) + { + } + +-void reset_vfio_bytes_transferred(void) ++void migration_reset_vfio_bytes_transferred(void) + { + } + #endif diff --git a/SOURCES/migration-Add-save_prepare-handler-to-struct-SaveVMHandlers.patch b/SOURCES/migration-Add-save_prepare-handler-to-struct-SaveVMHandlers.patch new file mode 100644 index 0000000..576c186 --- /dev/null +++ b/SOURCES/migration-Add-save_prepare-handler-to-struct-SaveVMHandlers.patch @@ -0,0 +1,158 @@ +From 08fc4cb51774f763dcc6fd74637aa9e00eb6a0ba Mon Sep 17 00:00:00 2001 +From: Avihai Horon +Date: Wed, 6 Sep 2023 18:08:51 +0300 +Subject: [PATCH] migration: Add .save_prepare() handler to struct + SaveVMHandlers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add a new .save_prepare() handler to struct SaveVMHandlers. This handler +is called early, even before migration starts, and can be used by +devices to perform early checks. + +Refactor migrate_init() to be able to return errors and call +.save_prepare() from there. + +Suggested-by: Peter Xu +Signed-off-by: Avihai Horon +Reviewed-by: Peter Xu +Reviewed-by: Cédric Le Goater +Signed-off-by: Cédric Le Goater +--- + include/migration/register.h | 5 +++++ + migration/migration.c | 15 +++++++++++++-- + migration/migration.h | 2 +- + migration/savevm.c | 29 ++++++++++++++++++++++++++++- + migration/savevm.h | 1 + + 5 files changed, 48 insertions(+), 4 deletions(-) + +diff --git a/include/migration/register.h b/include/migration/register.h +index 90914f32f50c..2b12c6adeca7 100644 +--- a/include/migration/register.h ++++ b/include/migration/register.h +@@ -20,6 +20,11 @@ typedef struct SaveVMHandlers { + /* This runs inside the iothread lock. */ + SaveStateHandler *save_state; + ++ /* ++ * save_prepare is called early, even before migration starts, and can be ++ * used to perform early checks. ++ */ ++ int (*save_prepare)(void *opaque, Error **errp); + void (*save_cleanup)(void *opaque); + int (*save_live_complete_postcopy)(QEMUFile *f, void *opaque); + int (*save_live_complete_precopy)(QEMUFile *f, void *opaque); +diff --git a/migration/migration.c b/migration/migration.c +index ce01a3ba6af7..d61e5727429a 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -1389,8 +1389,15 @@ bool migration_is_active(MigrationState *s) + s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE); + } + +-void migrate_init(MigrationState *s) ++int migrate_init(MigrationState *s, Error **errp) + { ++ int ret; ++ ++ ret = qemu_savevm_state_prepare(errp); ++ if (ret) { ++ return ret; ++ } ++ + /* + * Reinitialise all migration state, except + * parameters/capabilities that the user set, and +@@ -1429,6 +1436,8 @@ void migrate_init(MigrationState *s) + memset(&ram_counters, 0, sizeof(ram_counters)); + memset(&compression_counters, 0, sizeof(compression_counters)); + migration_reset_vfio_bytes_transferred(); ++ ++ return 0; + } + + int migrate_add_blocker_internal(Error *reason, Error **errp) +@@ -1638,7 +1647,9 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc, + migrate_set_block_incremental(s, true); + } + +- migrate_init(s); ++ if (migrate_init(s, errp)) { ++ return false; ++ } + + return true; + } +diff --git a/migration/migration.h b/migration/migration.h +index c5695de21496..c390500604b6 100644 +--- a/migration/migration.h ++++ b/migration/migration.h +@@ -465,7 +465,7 @@ void migrate_fd_connect(MigrationState *s, Error *error_in); + bool migration_is_setup_or_active(int state); + bool migration_is_running(int state); + +-void migrate_init(MigrationState *s); ++int migrate_init(MigrationState *s, Error **errp); + bool migration_is_blocked(Error **errp); + /* True if outgoing migration has entered postcopy phase */ + bool migration_in_postcopy(void); +diff --git a/migration/savevm.c b/migration/savevm.c +index e14efeced0fb..bb3e99194c60 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -1231,6 +1231,30 @@ bool qemu_savevm_state_guest_unplug_pending(void) + return false; + } + ++int qemu_savevm_state_prepare(Error **errp) ++{ ++ SaveStateEntry *se; ++ int ret; ++ ++ QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { ++ if (!se->ops || !se->ops->save_prepare) { ++ continue; ++ } ++ if (se->ops->is_active) { ++ if (!se->ops->is_active(se->opaque)) { ++ continue; ++ } ++ } ++ ++ ret = se->ops->save_prepare(se->opaque, errp); ++ if (ret < 0) { ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ + void qemu_savevm_state_setup(QEMUFile *f) + { + MigrationState *ms = migrate_get_current(); +@@ -1617,7 +1641,10 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp) + return -EINVAL; + } + +- migrate_init(ms); ++ ret = migrate_init(ms, errp); ++ if (ret) { ++ return ret; ++ } + ms->to_dst_file = f; + + qemu_mutex_unlock_iothread(); +diff --git a/migration/savevm.h b/migration/savevm.h +index e894bbc14331..74669733dd63 100644 +--- a/migration/savevm.h ++++ b/migration/savevm.h +@@ -31,6 +31,7 @@ + + bool qemu_savevm_state_blocked(Error **errp); + void qemu_savevm_non_migratable_list(strList **reasons); ++int qemu_savevm_state_prepare(Error **errp); + void qemu_savevm_state_setup(QEMUFile *f); + bool qemu_savevm_state_guest_unplug_pending(void); + int qemu_savevm_state_resume_prepare(MigrationState *s); diff --git a/SOURCES/migration-Move-more-initializations-to-migrate_init.patch b/SOURCES/migration-Move-more-initializations-to-migrate_init.patch new file mode 100644 index 0000000..8c7129d --- /dev/null +++ b/SOURCES/migration-Move-more-initializations-to-migrate_init.patch @@ -0,0 +1,68 @@ +From f543aa222da183ac37424d1ea3a65e5fb6202732 Mon Sep 17 00:00:00 2001 +From: Avihai Horon +Date: Wed, 6 Sep 2023 18:08:50 +0300 +Subject: [PATCH] migration: Move more initializations to migrate_init() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Initialization of mig_stats, compression_counters and VFIO bytes +transferred is hard-coded in migration code path and snapshot code path. + +Make the code cleaner by initializing them in migrate_init(). + +Suggested-by: Cédric Le Goater +Signed-off-by: Avihai Horon +Reviewed-by: Cédric Le Goater +Signed-off-by: Cédric Le Goater +--- + migration/migration.c | 14 +++++++------- + migration/savevm.c | 3 --- + 2 files changed, 7 insertions(+), 10 deletions(-) + +diff --git a/migration/migration.c b/migration/migration.c +index 92866a8f49d3..ce01a3ba6af7 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -1422,6 +1422,13 @@ void migrate_init(MigrationState *s) + s->iteration_initial_bytes = 0; + s->threshold_size = 0; + s->switchover_acked = false; ++ /* ++ * set mig_stats compression_counters memory to zero for a ++ * new migration ++ */ ++ memset(&ram_counters, 0, sizeof(ram_counters)); ++ memset(&compression_counters, 0, sizeof(compression_counters)); ++ migration_reset_vfio_bytes_transferred(); + } + + int migrate_add_blocker_internal(Error *reason, Error **errp) +@@ -1632,13 +1639,6 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc, + } + + migrate_init(s); +- /* +- * set ram_counters compression_counters memory to zero for a +- * new migration +- */ +- memset(&ram_counters, 0, sizeof(ram_counters)); +- memset(&compression_counters, 0, sizeof(compression_counters)); +- migration_reset_vfio_bytes_transferred(); + + return true; + } +diff --git a/migration/savevm.c b/migration/savevm.c +index 5bf8b59a7dfc..e14efeced0fb 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -1618,9 +1618,6 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp) + } + + migrate_init(ms); +- memset(&ram_counters, 0, sizeof(ram_counters)); +- memset(&compression_counters, 0, sizeof(compression_counters)); +- migration_reset_vfio_bytes_transferred(); + ms->to_dst_file = f; + + qemu_mutex_unlock_iothread(); diff --git a/SOURCES/vfio-migration-Block-VFIO-migration-with-postcopy-migration.patch b/SOURCES/vfio-migration-Block-VFIO-migration-with-postcopy-migration.patch new file mode 100644 index 0000000..6a0b7d9 --- /dev/null +++ b/SOURCES/vfio-migration-Block-VFIO-migration-with-postcopy-migration.patch @@ -0,0 +1,69 @@ +From bf7ef7a2da3e61dc104f26c679c9465e3fbe7dde Mon Sep 17 00:00:00 2001 +From: Avihai Horon +Date: Wed, 6 Sep 2023 18:08:52 +0300 +Subject: [PATCH] vfio/migration: Block VFIO migration with postcopy migration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +VFIO migration is not compatible with postcopy migration. A VFIO device +in the destination can't handle page faults for pages that have not been +sent yet. + +Doing such migration will cause the VM to crash in the destination: + +qemu-system-x86_64: VFIO_MAP_DMA failed: Bad address +qemu-system-x86_64: vfio_dma_map(0x55a28c7659d0, 0xc0000, 0xb000, 0x7f1b11a00000) = -14 (Bad address) +qemu: hardware error: vfio: DMA mapping failed, unable to continue + +To prevent this, block VFIO migration with postcopy migration. + +Reported-by: Yanghang Liu +Signed-off-by: Avihai Horon +Tested-by: Yanghang Liu +Reviewed-by: Peter Xu +Signed-off-by: Cédric Le Goater +--- + hw/vfio/migration.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c +index 71855468fe98..20994dc1d60b 100644 +--- a/hw/vfio/migration.c ++++ b/hw/vfio/migration.c +@@ -335,6 +335,27 @@ static bool vfio_precopy_supported(VFIODevice *vbasedev) + + /* ---------------------------------------------------------------------- */ + ++static int vfio_save_prepare(void *opaque, Error **errp) ++{ ++ VFIODevice *vbasedev = opaque; ++ ++ /* ++ * Snapshot doesn't use postcopy, so allow snapshot even if postcopy is on. ++ */ ++ if (runstate_check(RUN_STATE_SAVE_VM)) { ++ return 0; ++ } ++ ++ if (migrate_postcopy_ram()) { ++ error_setg( ++ errp, "%s: VFIO migration is not supported with postcopy migration", ++ vbasedev->name); ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ + static int vfio_save_setup(QEMUFile *f, void *opaque) + { + VFIODevice *vbasedev = opaque; +@@ -640,6 +661,7 @@ static bool vfio_switchover_ack_needed(void *opaque) + } + + static const SaveVMHandlers savevm_vfio_handlers = { ++ .save_prepare = vfio_save_prepare, + .save_setup = vfio_save_setup, + .save_cleanup = vfio_save_cleanup, + .state_pending_estimate = vfio_state_pending_estimate, diff --git a/SPECS/qemu-kvm.spec b/SPECS/qemu-kvm.spec index 1f992e8..0d6d98f 100644 --- a/SPECS/qemu-kvm.spec +++ b/SPECS/qemu-kvm.spec @@ -149,7 +149,7 @@ Obsoletes: %{name}-block-ssh <= %{epoch}:%{version} \ Summary: QEMU is a machine emulator and virtualizer Name: qemu-kvm Version: 8.0.0 -Release: 13%{?rcrel}%{?dist}%{?cc_suffix} +Release: 16%{?rcrel}%{?dist}%{?cc_suffix}.1.alma.1 # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped # Epoch 15 used for RHEL 8 # Epoch 17 used for RHEL 9 (due to release versioning offset in RHEL 8.5) @@ -548,6 +548,16 @@ Patch192: kvm-vdpa-move-vhost_vdpa_set_vring_ready-to-the-caller.patch Patch193: kvm-vdpa-remove-net-cvq-migration-blocker.patch # Patches were taken from upstream and backported to apply cleanly: +# https://github.com/qemu/qemu/commit/10be627d2b5ec2d6b3dce045144aa739eef678b4.patch +Patch1001: io-remove-io-watch-if-TLS-channel-is-closed.patch +# https://github.com/qemu/qemu/commit/38c482b4778595ee337761f73ec0730d6c47b404.patch +Patch1002: migration-Add-migration-prefix-to-functions-in-target.patch +# https://github.com/qemu/qemu/commit/f543aa222da183ac37424d1ea3a65e5fb6202732.patch +Patch1003: migration-Move-more-initializations-to-migrate_init.patch +# https://github.com/qemu/qemu/commit/08fc4cb51774f763dcc6fd74637aa9e00eb6a0ba.patch +Patch1004: migration-Add-save_prepare-handler-to-struct-SaveVMHandlers.patch +# https://github.com/qemu/qemu/commit/bf7ef7a2da3e61dc104f26c679c9465e3fbe7dde.patch +Patch1005: vfio-migration-Block-VFIO-migration-with-postcopy-migration.patch %if %{have_clang} BuildRequires: clang @@ -1609,6 +1619,13 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %endif %changelog +* Tue Nov 07 2023 Eduard Abdullin - 8.0.0-16.1.alma.1 +- Apply io-remove-io-watch-if-TLS-channel-is-closed.patch +- Apply migration-Add-migration-prefix-to-functions-in-target.patch +- Apply migration-Move-more-initializations-to-migrate_init.patch +- Apply migration-Add-save_prepare-handler-to-struct-SaveVMHandlers.patch +- Apply vfio-migration-Block-VFIO-migration-with-postcopy-migration.patch + * Thu Aug 24 2023 Miroslav Rezanina - 8.0.0-13 - kvm-vdpa-return-errno-in-vhost_vdpa_get_vring_group-erro.patch [RHEL-923] - kvm-vdpa-move-CVQ-isolation-check-to-net_init_vhost_vdpa.patch [RHEL-923]