diff --git a/SOURCES/kvm-arm-kvm-report-registers-we-failed-to-set.patch b/SOURCES/kvm-arm-kvm-report-registers-we-failed-to-set.patch new file mode 100644 index 0000000..d17acca --- /dev/null +++ b/SOURCES/kvm-arm-kvm-report-registers-we-failed-to-set.patch @@ -0,0 +1,154 @@ +From c58596d3eea1b98e5fccb6f00f207ce5bf3f90c8 Mon Sep 17 00:00:00 2001 +From: Cornelia Huck +Date: Thu, 11 Sep 2025 17:41:59 +0200 +Subject: [PATCH] arm/kvm: report registers we failed to set + +RH-Author: Eric Auger +RH-MergeRequest: 493: arm/kvm: report registers we failed to set +RH-Jira: RHEL-120502 +RH-Acked-by: Sebastian Ott +RH-Acked-by: Cornelia Huck +RH-Acked-by: Gavin Shan +RH-Acked-by: Donald Dutile +RH-Commit: [1/1] 20bfe1faca2dd944bd9afcb2e1c198f0a5723259 + +If we fail migration because of a mismatch of some registers between +source and destination, the error message is not very informative: + +qemu-system-aarch64: error while loading state for instance 0x0 ofdevice 'cpu' +qemu-system-aarch64: Failed to put registers after init: Invalid argument + +At least try to give the user a hint which registers had a problem, +even if they cannot really do anything about it right now. + +Sample output: + +Could not set register op0:3 op1:0 crn:0 crm:0 op2:0 to c00fac31 (is 413fd0c1) + +We could be even more helpful once we support writable ID registers, +at which point the user might actually be able to configure something +that is migratable. + +Suggested-by: Eric Auger +Reviewed-by: Sebastian Ott +Signed-off-by: Cornelia Huck +Message-id: 20250911154159.158046-1-cohuck@redhat.com +Signed-off-by: Peter Maydell +(cherry picked from commit 19f6dcfe6b8b2a3523362812fc696ab83050d316) +Signed-off-by: Eric Auger +--- + target/arm/kvm.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 86 insertions(+) + +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index e0469e7831..557cfcf670 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -923,6 +923,58 @@ bool write_kvmstate_to_list(ARMCPU *cpu) + return ok; + } + ++/* pretty-print a KVM register */ ++#define CP_REG_ARM64_SYSREG_OP(_reg, _op) \ ++ ((uint8_t)((_reg & CP_REG_ARM64_SYSREG_ ## _op ## _MASK) >> \ ++ CP_REG_ARM64_SYSREG_ ## _op ## _SHIFT)) ++ ++static gchar *kvm_print_sve_register_name(uint64_t regidx) ++{ ++ uint16_t sve_reg = regidx & 0x000000000000ffff; ++ ++ if (regidx == KVM_REG_ARM64_SVE_VLS) { ++ return g_strdup_printf("SVE VLS"); ++ } ++ /* zreg, preg, ffr */ ++ switch (sve_reg & 0xfc00) { ++ case 0: ++ return g_strdup_printf("SVE zreg n:%d slice:%d", ++ (sve_reg & 0x03e0) >> 5, sve_reg & 0x001f); ++ case 0x04: ++ return g_strdup_printf("SVE preg n:%d slice:%d", ++ (sve_reg & 0x01e0) >> 5, sve_reg & 0x001f); ++ case 0x06: ++ return g_strdup_printf("SVE ffr slice:%d", sve_reg & 0x001f); ++ default: ++ return g_strdup_printf("SVE ???"); ++ } ++} ++ ++static gchar *kvm_print_register_name(uint64_t regidx) ++{ ++ switch ((regidx & KVM_REG_ARM_COPROC_MASK)) { ++ case KVM_REG_ARM_CORE: ++ return g_strdup_printf("core reg %"PRIx64, regidx); ++ case KVM_REG_ARM_DEMUX: ++ return g_strdup_printf("demuxed reg %"PRIx64, regidx); ++ case KVM_REG_ARM64_SYSREG: ++ return g_strdup_printf("op0:%d op1:%d crn:%d crm:%d op2:%d", ++ CP_REG_ARM64_SYSREG_OP(regidx, OP0), ++ CP_REG_ARM64_SYSREG_OP(regidx, OP1), ++ CP_REG_ARM64_SYSREG_OP(regidx, CRN), ++ CP_REG_ARM64_SYSREG_OP(regidx, CRM), ++ CP_REG_ARM64_SYSREG_OP(regidx, OP2)); ++ case KVM_REG_ARM_FW: ++ return g_strdup_printf("fw reg %d", (int)(regidx & 0xffff)); ++ case KVM_REG_ARM64_SVE: ++ return kvm_print_sve_register_name(regidx); ++ case KVM_REG_ARM_FW_FEAT_BMAP: ++ return g_strdup_printf("fw feat reg %d", (int)(regidx & 0xffff)); ++ default: ++ return g_strdup_printf("%"PRIx64, regidx); ++ } ++} ++ + bool write_list_to_kvmstate(ARMCPU *cpu, int level) + { + CPUState *cs = CPU(cpu); +@@ -950,11 +1002,45 @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level) + g_assert_not_reached(); + } + if (ret) { ++ gchar *reg_str = kvm_print_register_name(regidx); ++ + /* We might fail for "unknown register" and also for + * "you tried to set a register which is constant with + * a different value from what it actually contains". + */ + ok = false; ++ switch (ret) { ++ case -ENOENT: ++ error_report("Could not set register %s: unknown to KVM", ++ reg_str); ++ break; ++ case -EINVAL: ++ if ((regidx & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U32) { ++ if (!kvm_get_one_reg(cs, regidx, &v32)) { ++ error_report("Could not set register %s to %x (is %x)", ++ reg_str, (uint32_t)cpu->cpreg_values[i], ++ v32); ++ } else { ++ error_report("Could not set register %s to %x", ++ reg_str, (uint32_t)cpu->cpreg_values[i]); ++ } ++ } else /* U64 */ { ++ uint64_t v64; ++ ++ if (!kvm_get_one_reg(cs, regidx, &v64)) { ++ error_report("Could not set register %s to %"PRIx64" (is %"PRIx64")", ++ reg_str, cpu->cpreg_values[i], v64); ++ } else { ++ error_report("Could not set register %s to %"PRIx64, ++ reg_str, cpu->cpreg_values[i]); ++ } ++ } ++ break; ++ default: ++ error_report("Could not set register %s: %s", ++ reg_str, strerror(-ret)); ++ } ++ g_free(reg_str); + } + } + return ok; +-- +2.50.1 + diff --git a/SOURCES/kvm-io-fix-use-after-free-in-websocket-handshake-code.patch b/SOURCES/kvm-io-fix-use-after-free-in-websocket-handshake-code.patch new file mode 100644 index 0000000..dec3bd5 --- /dev/null +++ b/SOURCES/kvm-io-fix-use-after-free-in-websocket-handshake-code.patch @@ -0,0 +1,189 @@ +From 9f1ce751f7e800f00e4511c6ec874fe38deba7bf Mon Sep 17 00:00:00 2001 +From: Jon Maloy +Date: Tue, 4 Nov 2025 17:28:47 -0500 +Subject: [PATCH 2/2] io: fix use after free in websocket handshake code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Jon Maloy +RH-MergeRequest: 497: io: fix use after free in websocket handshake code +RH-Jira: RHEL-120125 +RH-Acked-by: Daniel P. Berrangé +RH-Acked-by: Miroslav Rezanina +RH-Commit: [2/2] 68a23cb8e7a580a0d7de79994c71157f25c792ee (redhat/rhel/src/qemu-kvm/jons-qemu-kvm-2) + +JIRA: https://issues.redhat.com/browse/RHEL-120125 +CVE: CVE-2025-11234 + +commit b7a1f2ca45c7865b9e98e02ae605a65fc9458ae9 +Author: Daniel P. Berrangé +Date: Tue Sep 30 12:03:15 2025 +0100 + + io: fix use after free in websocket handshake code + + If the QIOChannelWebsock object is freed while it is waiting to + complete a handshake, a GSource is leaked. This can lead to the + callback firing later on and triggering a use-after-free in the + use of the channel. This was observed in the VNC server with the + following trace from valgrind: + + ==2523108== Invalid read of size 4 + ==2523108== at 0x4054A24: vnc_disconnect_start (vnc.c:1296) + ==2523108== by 0x4054A24: vnc_client_error (vnc.c:1392) + ==2523108== by 0x4068A09: vncws_handshake_done (vnc-ws.c:105) + ==2523108== by 0x44863B4: qio_task_complete (task.c:197) + ==2523108== by 0x448343D: qio_channel_websock_handshake_io (channel-websock.c:588) + ==2523108== by 0x6EDB862: UnknownInlinedFun (gmain.c:3398) + ==2523108== by 0x6EDB862: g_main_context_dispatch_unlocked.lto_priv.0 (gmain.c:4249) + ==2523108== by 0x6EDBAE4: g_main_context_dispatch (gmain.c:4237) + ==2523108== by 0x45EC79F: glib_pollfds_poll (main-loop.c:287) + ==2523108== by 0x45EC79F: os_host_main_loop_wait (main-loop.c:310) + ==2523108== by 0x45EC79F: main_loop_wait (main-loop.c:589) + ==2523108== by 0x423A56D: qemu_main_loop (runstate.c:835) + ==2523108== by 0x454F300: qemu_default_main (main.c:37) + ==2523108== by 0x73D6574: (below main) (libc_start_call_main.h:58) + ==2523108== Address 0x57a6e0dc is 28 bytes inside a block of size 103,608 free'd + ==2523108== at 0x5F2FE43: free (vg_replace_malloc.c:989) + ==2523108== by 0x6EDC444: g_free (gmem.c:208) + ==2523108== by 0x4053F23: vnc_update_client (vnc.c:1153) + ==2523108== by 0x4053F23: vnc_refresh (vnc.c:3225) + ==2523108== by 0x4042881: dpy_refresh (console.c:880) + ==2523108== by 0x4042881: gui_update (console.c:90) + ==2523108== by 0x45EFA1B: timerlist_run_timers.part.0 (qemu-timer.c:562) + ==2523108== by 0x45EFC8F: timerlist_run_timers (qemu-timer.c:495) + ==2523108== by 0x45EFC8F: qemu_clock_run_timers (qemu-timer.c:576) + ==2523108== by 0x45EFC8F: qemu_clock_run_all_timers (qemu-timer.c:663) + ==2523108== by 0x45EC765: main_loop_wait (main-loop.c:600) + ==2523108== by 0x423A56D: qemu_main_loop (runstate.c:835) + ==2523108== by 0x454F300: qemu_default_main (main.c:37) + ==2523108== by 0x73D6574: (below main) (libc_start_call_main.h:58) + ==2523108== Block was alloc'd at + ==2523108== at 0x5F343F3: calloc (vg_replace_malloc.c:1675) + ==2523108== by 0x6EE2F81: g_malloc0 (gmem.c:133) + ==2523108== by 0x4057DA3: vnc_connect (vnc.c:3245) + ==2523108== by 0x448591B: qio_net_listener_channel_func (net-listener.c:54) + ==2523108== by 0x6EDB862: UnknownInlinedFun (gmain.c:3398) + ==2523108== by 0x6EDB862: g_main_context_dispatch_unlocked.lto_priv.0 (gmain.c:4249) + ==2523108== by 0x6EDBAE4: g_main_context_dispatch (gmain.c:4237) + ==2523108== by 0x45EC79F: glib_pollfds_poll (main-loop.c:287) + ==2523108== by 0x45EC79F: os_host_main_loop_wait (main-loop.c:310) + ==2523108== by 0x45EC79F: main_loop_wait (main-loop.c:589) + ==2523108== by 0x423A56D: qemu_main_loop (runstate.c:835) + ==2523108== by 0x454F300: qemu_default_main (main.c:37) + ==2523108== by 0x73D6574: (below main) (libc_start_call_main.h:58) + ==2523108== + + The above can be reproduced by launching QEMU with + + $ qemu-system-x86_64 -vnc localhost:0,websocket=5700 + + and then repeatedly running: + + for i in {1..100}; do + (echo -n "GET / HTTP/1.1" && sleep 0.05) | nc -w 1 localhost 5700 & + done + + CVE-2025-11234 + Reported-by: Grant Millar | Cylo + Reviewed-by: Eric Blake + Signed-off-by: Daniel P. Berrangé + +Signed-off-by: Jon Maloy +--- + include/io/channel-websock.h | 3 ++- + io/channel-websock.c | 22 ++++++++++++++++------ + 2 files changed, 18 insertions(+), 7 deletions(-) + +diff --git a/include/io/channel-websock.h b/include/io/channel-websock.h +index e180827c57..6700cf8946 100644 +--- a/include/io/channel-websock.h ++++ b/include/io/channel-websock.h +@@ -61,7 +61,8 @@ struct QIOChannelWebsock { + size_t payload_remain; + size_t pong_remain; + QIOChannelWebsockMask mask; +- guint io_tag; ++ guint hs_io_tag; /* tracking handshake task */ ++ guint io_tag; /* tracking watch task */ + Error *io_err; + gboolean io_eof; + uint8_t opcode; +diff --git a/io/channel-websock.c b/io/channel-websock.c +index 1aac3c88a8..583ea86187 100644 +--- a/io/channel-websock.c ++++ b/io/channel-websock.c +@@ -545,6 +545,7 @@ static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc, + trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err)); + qio_task_set_error(task, err); + qio_task_complete(task); ++ wioc->hs_io_tag = 0; + return FALSE; + } + +@@ -560,6 +561,7 @@ static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc, + trace_qio_channel_websock_handshake_complete(ioc); + qio_task_complete(task); + } ++ wioc->hs_io_tag = 0; + return FALSE; + } + trace_qio_channel_websock_handshake_pending(ioc, G_IO_OUT); +@@ -586,6 +588,7 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc, + trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err)); + qio_task_set_error(task, err); + qio_task_complete(task); ++ wioc->hs_io_tag = 0; + return FALSE; + } + if (ret == 0) { +@@ -597,7 +600,7 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc, + error_propagate(&wioc->io_err, err); + + trace_qio_channel_websock_handshake_reply(ioc); +- qio_channel_add_watch( ++ wioc->hs_io_tag = qio_channel_add_watch( + wioc->master, + G_IO_OUT, + qio_channel_websock_handshake_send, +@@ -907,11 +910,12 @@ void qio_channel_websock_handshake(QIOChannelWebsock *ioc, + + trace_qio_channel_websock_handshake_start(ioc); + trace_qio_channel_websock_handshake_pending(ioc, G_IO_IN); +- qio_channel_add_watch(ioc->master, +- G_IO_IN, +- qio_channel_websock_handshake_io, +- task, +- NULL); ++ ioc->hs_io_tag = qio_channel_add_watch( ++ ioc->master, ++ G_IO_IN, ++ qio_channel_websock_handshake_io, ++ task, ++ NULL); + } + + +@@ -922,6 +926,9 @@ static void qio_channel_websock_finalize(Object *obj) + buffer_free(&ioc->encinput); + buffer_free(&ioc->encoutput); + buffer_free(&ioc->rawinput); ++ if (ioc->hs_io_tag) { ++ g_source_remove(ioc->hs_io_tag); ++ } + if (ioc->io_tag) { + g_source_remove(ioc->io_tag); + } +@@ -1222,6 +1229,9 @@ static int qio_channel_websock_close(QIOChannel *ioc, + buffer_free(&wioc->encinput); + buffer_free(&wioc->encoutput); + buffer_free(&wioc->rawinput); ++ if (wioc->hs_io_tag) { ++ g_clear_handle_id(&wioc->hs_io_tag, g_source_remove); ++ } + if (wioc->io_tag) { + g_clear_handle_id(&wioc->io_tag, g_source_remove); + } +-- +2.50.1 + diff --git a/SOURCES/kvm-io-move-websock-resource-release-to-close-method.patch b/SOURCES/kvm-io-move-websock-resource-release-to-close-method.patch new file mode 100644 index 0000000..ac68672 --- /dev/null +++ b/SOURCES/kvm-io-move-websock-resource-release-to-close-method.patch @@ -0,0 +1,84 @@ +From e4223fa468bf6887c3053a74a6e83bd0e99af70c Mon Sep 17 00:00:00 2001 +From: Jon Maloy +Date: Tue, 4 Nov 2025 17:23:29 -0500 +Subject: [PATCH 1/2] io: move websock resource release to close method +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Jon Maloy +RH-MergeRequest: 497: io: fix use after free in websocket handshake code +RH-Jira: RHEL-120125 +RH-Acked-by: Daniel P. Berrangé +RH-Acked-by: Miroslav Rezanina +RH-Commit: [1/2] 09d2c8d9150af559afb5750b97b1b6985e535580 (redhat/rhel/src/qemu-kvm/jons-qemu-kvm-2) + +JIRA: https://issues.redhat.com/browse/RHEL-120125 +CVE: CVE-2025-11234 + +commit 322c3c4f3abee616a18b3bfe563ec29dd67eae63 +Author: Daniel P. Berrangé +Date: Tue Sep 30 11:58:35 2025 +0100 + + io: move websock resource release to close method + + The QIOChannelWebsock object releases all its resources in the + finalize callback. This is later than desired, as callers expect + to be able to call qio_channel_close() to fully close a channel + and release resources related to I/O. + + The logic in the finalize method is at most a failsafe to handle + cases where a consumer forgets to call qio_channel_close. + + This adds equivalent logic to the close method to release the + resources, using g_clear_handle_id/g_clear_pointer to be robust + against repeated invocations. The finalize method is tweaked + so that the GSource is removed before releasing the underlying + channel. + + Reviewed-by: Eric Blake + Signed-off-by: Daniel P. Berrangé + +Signed-off-by: Jon Maloy +--- + io/channel-websock.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/io/channel-websock.c b/io/channel-websock.c +index de39f0d182..1aac3c88a8 100644 +--- a/io/channel-websock.c ++++ b/io/channel-websock.c +@@ -922,13 +922,13 @@ static void qio_channel_websock_finalize(Object *obj) + buffer_free(&ioc->encinput); + buffer_free(&ioc->encoutput); + buffer_free(&ioc->rawinput); +- object_unref(OBJECT(ioc->master)); + if (ioc->io_tag) { + g_source_remove(ioc->io_tag); + } + if (ioc->io_err) { + error_free(ioc->io_err); + } ++ object_unref(OBJECT(ioc->master)); + } + + +@@ -1219,6 +1219,15 @@ static int qio_channel_websock_close(QIOChannel *ioc, + QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); + + trace_qio_channel_websock_close(ioc); ++ buffer_free(&wioc->encinput); ++ buffer_free(&wioc->encoutput); ++ buffer_free(&wioc->rawinput); ++ if (wioc->io_tag) { ++ g_clear_handle_id(&wioc->io_tag, g_source_remove); ++ } ++ if (wioc->io_err) { ++ g_clear_pointer(&wioc->io_err, error_free); ++ } + return qio_channel_close(wioc->master, errp); + } + +-- +2.50.1 + diff --git a/SPECS/qemu-kvm.spec b/SPECS/qemu-kvm.spec index 8d8a946..c02fe7a 100644 --- a/SPECS/qemu-kvm.spec +++ b/SPECS/qemu-kvm.spec @@ -151,7 +151,7 @@ Obsoletes: %{name}-block-ssh <= %{epoch}:%{version} \ Summary: QEMU is a machine emulator and virtualizer Name: qemu-kvm Version: 9.1.0 -Release: 29%{?rcrel}%{?dist}%{?cc_suffix}.alma.1 +Release: 29%{?rcrel}%{?dist}%{?cc_suffix}.3.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) @@ -1201,12 +1201,18 @@ Patch391: kvm-ram-block-attributes-Introduce-RamBlockAttributes-to.patch Patch392: kvm-physmem-Support-coordinated-discarding-of-RAM-with-g.patch # For RHEL-17614 - VM reports Vulnerable to spec_rstack_overflow when reading status in '/sys/devices/system/cpu/vulnerabilities/' Patch393: kvm-target-i386-Expose-IBPB-BRTYPE-and-SBPB-CPUID-bits-t.patch +# For RHEL-120502 - [rhel9] Backport "arm/kvm: report registers we failed to set" [rhel-9.7.z] +Patch394: kvm-arm-kvm-report-registers-we-failed-to-set.patch +# For RHEL-120125 - CVE-2025-11234 qemu-kvm: VNC WebSocket handshake use-after-free [rhel-9.7.z] +Patch395: kvm-io-move-websock-resource-release-to-close-method.patch +# For RHEL-120125 - CVE-2025-11234 qemu-kvm: VNC WebSocket handshake use-after-free [rhel-9.7.z] +Patch396: kvm-io-fix-use-after-free-in-websocket-handshake-code.patch # AlmaLinux Patch -Patch394: 0001-Bring-back-missing-line-in-target-ppc-cpu-models.patch -Patch395: 0001-usb-add-config-options-for-hub-and-hid-devices-for-p.patch -Patch396: 0001-Add-AlmaLinux-9-to-machine-class-options.patch -Patch397: osuosl-enable-ppc64.patch +Patch397: 0001-Bring-back-missing-line-in-target-ppc-cpu-models.patch +Patch398: 0001-usb-add-config-options-for-hub-and-hid-devices-for-p.patch +Patch399: 0001-Add-AlmaLinux-9-to-machine-class-options.patch +Patch400: osuosl-enable-ppc64.patch %if %{have_clang} BuildRequires: clang @@ -2295,11 +2301,28 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %endif %changelog -* Mon Oct 20 2025 Eduard Abdullin - 17:9.1.0-29.alma.1 +* Mon Dec 22 2025 Eduard Abdullin - 17:9.1.0-29.3.alma.1 - Enable building for ppc64le - Don't remove slof.bin for ppc64le - usb: add config options for hub and hid devices for ppc +* Mon Nov 17 2025 Jon Maloy - 9.1.0-29.el9_7.3 +- kvm-io-move-websock-resource-release-to-close-method.patch [RHEL-120125] +- kvm-io-fix-use-after-free-in-websocket-handshake-code.patch [RHEL-120125] +- Resolves: RHEL-120125 + (CVE-2025-11234 qemu-kvm: VNC WebSocket handshake use-after-free [rhel-9.7.z]) + +* Wed Nov 12 2025 Jon Maloy - 9.1.0-29.el9_7.2 +- kvm-io-move-websock-resource-release-to-close-method.patch [RHEL-120125] +- kvm-io-fix-use-after-free-in-websocket-handshake-code.patch [RHEL-120125] +- Resolves: RHEL-120125 + (CVE-2025-11234 qemu-kvm: VNC WebSocket handshake use-after-free [rhel-9.7.z]) + +* Mon Nov 03 2025 Jon Maloy - 9.1.0-29.el9_7.1 +- kvm-arm-kvm-report-registers-we-failed-to-set.patch [RHEL-120502] +- Resolves: RHEL-120502 + ([rhel9] Backport "arm/kvm: report registers we failed to set" [rhel-9.7.z]) + * Tue Sep 16 2025 Jon Maloy - 9.1.0-29 - kvm-target-i386-Expose-IBPB-BRTYPE-and-SBPB-CPUID-bits-t.patch [RHEL-17614] - Resolves: RHEL-17614