* [PULL 01/10] docs: Add security considerations for migration
2026-08-12 15:14 [PULL 00/10] Next patches Peter Xu
@ 2026-08-12 15:14 ` Peter Xu
2026-08-12 15:14 ` [PULL 02/10] migration/cpr: Add HMP support for cpr-transfer Peter Xu
` (9 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Peter Xu @ 2026-08-12 15:14 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Fabiano Rosas, Paolo Bonzini, Daniel P. Berrangé
From: Fabiano Rosas <farosas@suse.de>
Add the security considerations that are unique to migration and that
do not already fall into one of the other categories. Some aspects are
better framed as security architecture considerations, so extend that
section to mention TLS and clarify that disk images and guest network
also need to be isolated from other processes, not just other guests.
Reviewed-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
Link: https://lore.kernel.org/r/20260721131457.3062767-1-farosas@suse.de
Signed-off-by: Peter Xu <peterx@redhat.com>
---
docs/system/security.rst | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/docs/system/security.rst b/docs/system/security.rst
index 52bbf0cc7a..af626a4230 100644
--- a/docs/system/security.rst
+++ b/docs/system/security.rst
@@ -133,6 +133,16 @@ an issue as a normal bug.
that affect the level 0 QEMU process. While these bugs should be
fixed, they will not be triaged as security flaws at this time.
+* **migration/snapshots**. Migration failures and snapshot load
+ failures are considered part of normal operation as long as the
+ source virtual machine and savevm file, respectively, are still
+ functional. Aborting the QEMU process at the migration/snapshot
+ destination is similarly not considered a security issue. The
+ migration stream is assumed to be secure as long as the design
+ principles described in the Architecture section are held, in
+ which case plain manipulation of the stream is not considered as
+ an attack vector.
+
* **low severity impact**. As a catch all rule, issues which
are judged to have a "low" severity impact on the system will
usually not justify handling as security bugs, nor assignment
@@ -159,10 +169,11 @@ could allow malicious guests to gain code execution in QEMU. At this point the
guest has escaped the virtual machine and is able to act in the context of the
QEMU process on the host.
-Guests often interact with other guests and share resources with them. A
-malicious guest must not gain control of other guests or access their data.
-Disk image files and network traffic must be protected from other guests unless
-explicitly shared between them by the user.
+Guests often interact with other guests and share resources with them.
+A malicious guest must not gain control of other guests or access
+their data. Disk image files and network traffic must be protected
+from other guests, users and processes unless explicitly shared with
+them by the user.
Principle of Least Privilege
''''''''''''''''''''''''''''
@@ -223,6 +234,9 @@ Some Linux distros already ship with UNIX groups for these devices by default.
system calls that are not needed by QEMU, thereby reducing the host kernel
attack surface.
+- Transport Layer Security (TLS) protocol can be used to ensure authenticity and
+ encryption of the live migration connection where the network is untrusted.
+
Sensitive configurations
------------------------
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PULL 02/10] migration/cpr: Add HMP support for cpr-transfer
2026-08-12 15:14 [PULL 00/10] Next patches Peter Xu
2026-08-12 15:14 ` [PULL 01/10] docs: Add security considerations for migration Peter Xu
@ 2026-08-12 15:14 ` Peter Xu
2026-08-12 15:14 ` [PULL 03/10] system/memory: Use memmove() for directly accessible regions Peter Xu
` (8 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Peter Xu @ 2026-08-12 15:14 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Fabiano Rosas, Paolo Bonzini, Dongli Zhang,
Dr. David Alan Gilbert, Maciej S. Szmigiero
From: Dongli Zhang <dongli.zhang@oracle.com>
Currently the cpr-transfer source QEMU instance cannot be driven entirely
via HMP. The source must use QMP in order to specify both the
main migration channel and the CPR channel.
Extend the HMP migrate command with an optional CPR channel URI. When the
migration mode is cpr-transfer, HMP uses this URI to build a
CPR MigrationChannel in addition to the main migration channel. The new
option is rejected unless the migration mode is cpr-transfer, so existing
HMP migrate usage is unchanged.
For example, source QEMU HMP commands can be something like below. The
"-c unix:/tmp/cpr.sock" is for CPR URI.
(qemu) migrate_set_parameter mode cpr-transfer
(qemu) migrate -c unix:/tmp/cpr.sock tcp:0:50002
Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com>
Reviewed-by: Dr. David Alan Gilbert <dave@treblig.org>
Acked-by: Maciej S. Szmigiero <maciej.szmigiero@oracle.com>
Link: https://lore.kernel.org/r/20260728085903.173265-1-dongli.zhang@oracle.com
Signed-off-by: Peter Xu <peterx@redhat.com>
---
migration/migration-hmp-cmds.c | 18 ++++++++++++++++++
hmp-commands.hx | 12 ++++++++----
2 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index b04fc4489f..b5eb27467c 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -837,9 +837,11 @@ void hmp_migrate(Monitor *mon, const QDict *qdict)
bool detach = qdict_get_try_bool(qdict, "detach", false);
bool resume = qdict_get_try_bool(qdict, "resume", false);
const char *uri = qdict_get_str(qdict, "uri");
+ const char *uri_cpr = qdict_get_try_str(qdict, "uri-cpr");
Error *err = NULL;
g_autoptr(MigrationChannelList) caps = NULL;
g_autoptr(MigrationChannel) channel = NULL;
+ g_autoptr(MigrationChannel) channel_cpr = NULL;
if (!migrate_uri_parse(uri, &channel, &err)) {
hmp_handle_error(mon, err);
@@ -847,6 +849,22 @@ void hmp_migrate(Monitor *mon, const QDict *qdict)
}
QAPI_LIST_PREPEND(caps, g_steal_pointer(&channel));
+ if (uri_cpr) {
+ if (migrate_mode() != MIG_MODE_CPR_TRANSFER) {
+ error_setg(&err, "-c can only be used in cpr-transfer mode");
+ hmp_handle_error(mon, err);
+ return;
+ }
+
+ if (!migrate_uri_parse(uri_cpr, &channel_cpr, &err)) {
+ hmp_handle_error(mon, err);
+ return;
+ }
+
+ channel_cpr->channel_type = MIGRATION_CHANNEL_TYPE_CPR;
+ QAPI_LIST_PREPEND(caps, g_steal_pointer(&channel_cpr));
+ }
+
qmp_migrate(NULL, true, caps, true, resume, &err);
if (hmp_handle_error(mon, err)) {
return;
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 7ae2468a3d..7f43cf537f 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -928,16 +928,17 @@ ERST
{
.name = "migrate",
- .args_type = "detach:-d,resume:-r,uri:s",
- .params = "[-d] [-r] uri",
+ .args_type = "detach:-d,resume:-r,uri-cpr:-cs,uri:s",
+ .params = "[-d] [-r] [-c uri-cpr] uri",
.help = "migrate to URI (using -d to not wait for completion)"
- "\n\t\t\t -r to resume a paused postcopy migration",
+ "\n\t\t\t -r to resume a paused postcopy migration"
+ "\n\t\t\t -c to specify a CPR URI for cpr-transfer mode",
.cmd = hmp_migrate,
},
SRST
-``migrate [-d] [-r]`` *uri*
+``migrate [-d] [-r] [-c uri-cpr]`` *uri*
Migrate the VM to *uri*.
``-d``
@@ -945,6 +946,9 @@ SRST
query an ongoing migration process, use "info migrate".
``-r``
Resume a paused postcopy migration.
+ ``-c`` *uri-cpr*
+ Specify the CPR URI for cpr-transfer mode. It must be a UNIX domain
+ socket.
ERST
{
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PULL 03/10] system/memory: Use memmove() for directly accessible regions
2026-08-12 15:14 [PULL 00/10] Next patches Peter Xu
2026-08-12 15:14 ` [PULL 01/10] docs: Add security considerations for migration Peter Xu
2026-08-12 15:14 ` [PULL 02/10] migration/cpr: Add HMP support for cpr-transfer Peter Xu
@ 2026-08-12 15:14 ` Peter Xu
2026-08-12 15:14 ` [PULL 04/10] system/memory: Use qemu_ram_move() " Peter Xu
` (7 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Peter Xu @ 2026-08-12 15:14 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Fabiano Rosas, Paolo Bonzini, Gavin Shan, Peter Maydell
From: Gavin Shan <gshan@redhat.com>
Similar to what's done in commit 4a73aee88140 ("softmmu: Use memmove in
flatview_write_continue"), there are more sites where the overlapping
source and destination buffer are allowed for the directly accessible
regions. Use memmove() in those sites, listed as below.
hw/remote/vfio-user-obj.c::vfu_object_mr_rw
include/system/memory.h::address_space_read
system/physmem.c::flatview_read_continue_step
Signed-off-by: Gavin Shan <gshan@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Xu <peterx@redhat.com>
Link: https://lore.kernel.org/r/20260728031731.286666-2-gshan@redhat.com
Signed-off-by: Peter Xu <peterx@redhat.com>
---
include/system/memory.h | 2 +-
hw/remote/vfio-user-obj.c | 4 ++--
system/physmem.c | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/include/system/memory.h b/include/system/memory.h
index 2192fc9bdc..336d4e84a6 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -2741,7 +2741,7 @@ MemTxResult address_space_read(const AddressSpace *as, hwaddr addr,
mr = flatview_translate(fv, addr, &addr1, &l, false, attrs);
if (len == l && memory_access_is_direct(mr, false, attrs)) {
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
- memcpy(buf, ptr, len);
+ memmove(buf, ptr, len);
} else {
result = flatview_read_continue(fv, addr, attrs, buf, len,
addr1, l, mr);
diff --git a/hw/remote/vfio-user-obj.c b/hw/remote/vfio-user-obj.c
index 87fa7b6572..ea50270628 100644
--- a/hw/remote/vfio-user-obj.c
+++ b/hw/remote/vfio-user-obj.c
@@ -375,9 +375,9 @@ static int vfu_object_mr_rw(MemoryRegion *mr, uint8_t *buf, hwaddr offset,
ram_ptr = memory_region_get_ram_ptr(mr);
if (is_write) {
- memcpy((ram_ptr + offset), buf, size);
+ memmove((ram_ptr + offset), buf, size);
} else {
- memcpy(buf, (ram_ptr + offset), size);
+ memmove(buf, (ram_ptr + offset), size);
}
return 0;
diff --git a/system/physmem.c b/system/physmem.c
index c21ea92915..2c42e365cb 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -3363,7 +3363,7 @@ static MemTxResult flatview_read_continue_step(MemTxAttrs attrs, uint8_t *buf,
uint8_t *ram_ptr = qemu_ram_ptr_length(mr->ram_block, mr_addr, l,
false, false);
- memcpy(buf, ram_ptr, *l);
+ memmove(buf, ram_ptr, *l);
return MEMTX_OK;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PULL 04/10] system/memory: Use qemu_ram_move() for directly accessible regions
2026-08-12 15:14 [PULL 00/10] Next patches Peter Xu
` (2 preceding siblings ...)
2026-08-12 15:14 ` [PULL 03/10] system/memory: Use memmove() for directly accessible regions Peter Xu
@ 2026-08-12 15:14 ` Peter Xu
2026-08-12 15:14 ` [PULL 05/10] system/memory: Make ram device region directly accessible Peter Xu
` (6 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Peter Xu @ 2026-08-12 15:14 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Fabiano Rosas, Paolo Bonzini, Gavin Shan, Julia Graham,
Liu Gang, Ding Hui, Michael S. Tsirkin, Richard Henderson,
Peter Maydell
From: Gavin Shan <gshan@redhat.com>
All ram device regions were turned to be indirectly accessible by commit
4a2e242bbb ("memory: Don't use memcpy for ram_device regions"). This leads
to guest hang on attempt to build 'cuda-samples' as reported by Julia. The
guest is started by the following command lines, with GH100 GPU card passed
from the host.
host$ lspci | grep GH100
0009:01:00.0 3D controller: NVIDIA Corporation GH100 [GH200 120GB / 480GB] (rev a1)
host$ /home/sandbox/gavin/qemu.main/build/qemu-system-aarch64 \
-machine virt,gic-version=host,ras=on,highmem-mmio-size=4T \
-accel kvm -cpu host -smp cpus=48 -m size=8G \
-drive file=/home/gavin/sandbox/images/disk.qcow2,if=none,id=d0 \
-device virtio-blk-pci,id=vb0,bus=pcie.0,drive=d0,num-queues=4 \
-device vfio-pci-nohotplug,host=0009:01:00.0,bus=pcie.1.0
:
guest$ cd cuda-samples/build
guest$ make -j 20 clean
guest$ make -j 20
:
[ 54%] Linking CUDA executable graphMemoryNodes
[ 54%] Built target graphMemoryNodes
<no more output afterwards, guest becomes frozen here>
guest$ qemu-system-aarch64: virtio: bogus descriptor or out of resources
[ 555.814025] virtio_blk virtio0: [vda] new size: 268435456 512-byte logical blocks (137 GB/128 GiB)
When the GPU's driver (NVidia open driver) is loaded on guest bootup,
the memory blocks residing in the PCI BAR#4 of the GH100 GPU card can
be presented to the guest through memory hot-add. The page cache can
then be allocated from the hot added memory blocks when cuda-samples
is being built. Afterwards, the page cache is sent to QEMU's virtio-blk
device as part of the DMA request, the bounce buffer has to be used to
accomodate the request as the corresponding memory region (MemoryRegion)
is an indirectly accessible ram device region in qemu. However, the max
bounce bufer size is only 4096 bytes by default and that is exhausted
quickly, leading to a reset on the virtio-blk device and frozen guest
eventually.
QEMU
====
virtio_blk_handle_output
virtio_blk_handle_vq
virtio_blk_get_request
virtqueue_pop
virtqueue_split_pop
virtqueue_map_desc
address_space_map
memory_access_is_direct # Return false
memory_region_supports_direct_access
(qemu) info mtree
memory-region: pci_bridge_pci
0000000000000000-ffffffffffffffff (prio 0, container): pci_bridge_pci
0000042000000000-0000043fffffffff (prio 1, i/o): 0009:01:00.0 base BAR 4
0000042000000000-0000043fffffffff (prio 0, i/o): 0009:01:00.0 BAR 4
0000042000000000-000004379fffffff (prio 0, ramd): 0009:01:00.0 BAR 4 mmaps[0]
This adds qemu_ram_move() where the aligned and small-sized accesses are
handled by qatomics, and fall back to memmove() otherwise. The memove()
for the directly accessible regions is replaced by qemu_ram_move() so that
the issue covered by commit 4a2e242bbb (MMIO access instructions were
optimized to SSE instructions) is fixed. This makes 'ram_device_mem_ops'
redundant, paving the way to revert that commit to make the ram device
region directly accessible again in the next patch.
Besides, this also fixes the issue of the unexpected frozen reception on
e1000 NIC in the scenario of DPDK due to the wrong Rx queue full indication
caused by the following memcpy(), which is turned to 3 consective 'strb'
instructions to the same location by glibc-2.24+ for aarch64. With this
applied, the syntax of one-byte store is strictly ensured by a one-byte
qatomic set.
QEMU
====
e1000_receive_iov
pci_dma_write
pci_dma_rw
dma_memory_rw
dma_memory_rw_relaxed
address_space_rw
address_space_write
flatview_write
flatview_write_continue
flatview_write_continue_step
memcpy # 3 consective 'strb' instructions
Reported-by: Julia Graham <jugraham@redhat.com>
Reported-by: Liu Gang <liugang24219@sangfor.com.cn>
Reported-by: Ding Hui <dinghui@sangfor.com.cn>
Suggested-by: Michael S. Tsirkin <mst@redhat.com>
Suggested-by: Peter Xu <peterx@redhat.com>
Suggested-by: Richard Henderson <richard.henderson@linaro.org>
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Gavin Shan <gshan@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Link: https://lore.kernel.org/r/20260728031731.286666-3-gshan@redhat.com
[peterx: remove src==dst check, fix doc, enhance comments, per PeterM, add R-b]
Signed-off-by: Peter Xu <peterx@redhat.com>
---
include/system/memory.h | 35 +++++++++++++++++++++++++++-
hw/remote/vfio-user-obj.c | 4 ++--
system/physmem.c | 48 +++++++++++++++++++++++++++++++++++++--
3 files changed, 82 insertions(+), 5 deletions(-)
diff --git a/include/system/memory.h b/include/system/memory.h
index 336d4e84a6..4de5bf2577 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -2668,6 +2668,39 @@ void address_space_register_map_client(AddressSpace *as, QEMUBH *bh);
void address_space_unregister_map_client(AddressSpace *as, QEMUBH *bh);
/* Internal functions, part of the implementation of address_space_read. */
+
+/**
+ * qemu_ram_move: move data from or to ramblock
+ *
+ * @dst: destination where the data is moved to
+ * @src: source where the data is moved from
+ * @n: length of data to be moved
+ *
+ * Move @n bytes from @src to @dst, the memory areas may overlap. This
+ * provides the same semantics as memmove(), plus an additional stronger
+ * guarantee: if @n is 1, 2 or 4 or 8 bytes, and @src and @dst are both
+ * naturally aligned for that access size, then both the load and the store
+ * will be done as a single atomic access (with the semantics of
+ * qatomic_read() and qatomic_set()).
+ *
+ * This is the underlying function that we use to implement accesses by
+ * a guest vCPU or a device DMA operation to a ram block. The atomic
+ * guarantee is needed for two major cases: (A) When the ram block is
+ * backed by a PCI BAR passed through from a host device (and so it might
+ * be hardware registers that must be accessed exactly once at the right
+ * width); (B) When an emulated device updates a data structure shared in
+ * guest memory with guest software (e.g. a network device's set of tx and
+ * rx descriptor blocks), if a write to memory is accidentally performed
+ * multiple times then it can break the guest code when it busy polls the
+ * guest memory.
+ *
+ * We don't attempt to perform the exact access when it would be unaligned
+ * because this can't be done on all host architectures. Although this is
+ * strictly speaking not doing what would happen on real hardware, we don't
+ * think there are going to be situations where that matters in practice.
+ */
+void qemu_ram_move(void *dst, const void *src, size_t n);
+
MemTxResult address_space_read_full(const AddressSpace *as, hwaddr addr,
MemTxAttrs attrs, void *buf, hwaddr len);
MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
@@ -2741,7 +2774,7 @@ MemTxResult address_space_read(const AddressSpace *as, hwaddr addr,
mr = flatview_translate(fv, addr, &addr1, &l, false, attrs);
if (len == l && memory_access_is_direct(mr, false, attrs)) {
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
- memmove(buf, ptr, len);
+ qemu_ram_move(buf, ptr, len);
} else {
result = flatview_read_continue(fv, addr, attrs, buf, len,
addr1, l, mr);
diff --git a/hw/remote/vfio-user-obj.c b/hw/remote/vfio-user-obj.c
index ea50270628..a0498d218f 100644
--- a/hw/remote/vfio-user-obj.c
+++ b/hw/remote/vfio-user-obj.c
@@ -375,9 +375,9 @@ static int vfu_object_mr_rw(MemoryRegion *mr, uint8_t *buf, hwaddr offset,
ram_ptr = memory_region_get_ram_ptr(mr);
if (is_write) {
- memmove((ram_ptr + offset), buf, size);
+ qemu_ram_move((ram_ptr + offset), buf, size);
} else {
- memmove(buf, (ram_ptr + offset), size);
+ qemu_ram_move(buf, (ram_ptr + offset), size);
}
return 0;
diff --git a/system/physmem.c b/system/physmem.c
index 2c42e365cb..2f37cbeb07 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -3158,6 +3158,50 @@ void memory_region_flush_rom_device(MemoryRegion *mr, hwaddr addr, hwaddr size)
invalidate_and_set_dirty(mr, addr, size);
}
+void qemu_ram_move(void *dst, const void *src, size_t n)
+{
+ uintptr_t test, len;
+
+ if (n == 0) {
+ return;
+ }
+
+ /*
+ * Calculate "the lowest set bit" over @src, @dst and @n, result put
+ * into @len (which guarantees a power-of-two). With that and the
+ * later check (len!=n), it makes sure that we will only do the atomic
+ * ops when:
+ *
+ * (1) @n is a power-of-two
+ * (2) @src and @dst addresses are both aligned to @n
+ */
+ test = (uintptr_t)src | (uintptr_t)dst | n;
+ len = test & -test;
+
+ /* Overlapping buffers, unaligned or oversized access */
+ if (n > 8 || len != n) {
+ memmove(dst, src, n);
+ return;
+ }
+
+ switch (len) {
+ case 1:
+ qatomic_set((uint8_t *)dst, qatomic_read((uint8_t *)src));
+ break;
+ case 2:
+ qatomic_set((uint16_t *)dst, qatomic_read((uint16_t *)src));
+ break;
+ case 4:
+ qatomic_set((uint32_t *)dst, qatomic_read((uint32_t *)src));
+ break;
+ case 8:
+ qatomic_set((uint64_t *)dst, qatomic_read((uint64_t *)src));
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
{
unsigned access_size_max = mr->ops->valid.max_access_size;
@@ -3270,7 +3314,7 @@ static MemTxResult flatview_write_continue_step(MemTxAttrs attrs,
uint8_t *ram_ptr = qemu_ram_ptr_length(mr->ram_block, mr_addr, l,
false, true);
- memmove(ram_ptr, buf, *l);
+ qemu_ram_move(ram_ptr, buf, *l);
invalidate_and_set_dirty(mr, mr_addr, *l);
return MEMTX_OK;
@@ -3363,7 +3407,7 @@ static MemTxResult flatview_read_continue_step(MemTxAttrs attrs, uint8_t *buf,
uint8_t *ram_ptr = qemu_ram_ptr_length(mr->ram_block, mr_addr, l,
false, false);
- memmove(buf, ram_ptr, *l);
+ qemu_ram_move(buf, ram_ptr, *l);
return MEMTX_OK;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PULL 05/10] system/memory: Make ram device region directly accessible
2026-08-12 15:14 [PULL 00/10] Next patches Peter Xu
` (3 preceding siblings ...)
2026-08-12 15:14 ` [PULL 04/10] system/memory: Use qemu_ram_move() " Peter Xu
@ 2026-08-12 15:14 ` Peter Xu
2026-08-12 15:14 ` [PULL 06/10] tests/qtest/migration: Only build tls_no_hostname test with TASN1 Peter Xu
` (5 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Peter Xu @ 2026-08-12 15:14 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Fabiano Rosas, Paolo Bonzini, Gavin Shan, Julia Graham,
Michael S. Tsirkin, Richard Henderson, Peter Maydell
From: Gavin Shan <gshan@redhat.com>
This basically reverts 4a2e242bbb30 ("memory: Don't use memcpy for
ram_device regions") to make ram device region directly accessible
again. With this, the bounce buffer is bypassed in address_space_map()
when a ram device region is involved, potentially avoid to overrun
the (small) bounce buffer.
Reported-by: Julia Graham <jugraham@redhat.com>
Suggested-by: Michael S. Tsirkin <mst@redhat.com>
Suggested-by: Peter Xu <peterx@redhat.com>
Suggested-by: Richard Henderson <richard.henderson@linaro.org>
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Gavin Shan <gshan@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Link: https://lore.kernel.org/r/20260728031731.286666-4-gshan@redhat.com
Signed-off-by: Peter Xu <peterx@redhat.com>
---
include/system/memory.h | 11 ++---------
system/memory.c | 41 +----------------------------------------
system/trace-events | 2 --
3 files changed, 3 insertions(+), 51 deletions(-)
diff --git a/include/system/memory.h b/include/system/memory.h
index 4de5bf2577..1dc761058f 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -2718,15 +2718,8 @@ static inline bool memory_region_supports_direct_access(const MemoryRegion *mr)
if (memory_region_is_romd(mr)) {
return true;
}
- if (!memory_region_is_ram(mr)) {
- return false;
- }
- /*
- * RAM DEVICE regions can be accessed directly using memcpy, but it might
- * be MMIO and access using mempy can be wrong (e.g., using instructions not
- * intended for MMIO access). So we treat this as IO.
- */
- return !memory_region_is_ram_device(mr);
+
+ return memory_region_is_ram(mr);
}
static inline bool memory_access_is_direct(const MemoryRegion *mr,
diff --git a/system/memory.c b/system/memory.c
index 5fc36708ec..da710bbade 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -1364,43 +1364,6 @@ const MemoryRegionOps unassigned_mem_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static uint64_t memory_region_ram_device_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- MemoryRegion *mr = opaque;
- uint64_t data = ldn_he_p(mr->ram_block->host + addr, size);
-
- trace_memory_region_ram_device_read(get_cpu_index(), mr, addr, data, size);
-
- return data;
-}
-
-static void memory_region_ram_device_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- MemoryRegion *mr = opaque;
-
- trace_memory_region_ram_device_write(get_cpu_index(), mr, addr, data, size);
-
- stn_he_p(mr->ram_block->host + addr, size, data);
-}
-
-static const MemoryRegionOps ram_device_mem_ops = {
- .read = memory_region_ram_device_read,
- .write = memory_region_ram_device_write,
- .endianness = HOST_BIG_ENDIAN ? DEVICE_BIG_ENDIAN : DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 8,
- .unaligned = true,
- },
- .impl = {
- .min_access_size = 1,
- .max_access_size = 8,
- .unaligned = true,
- },
-};
-
bool memory_region_access_valid(MemoryRegion *mr,
hwaddr addr,
unsigned size,
@@ -1692,10 +1655,8 @@ void memory_region_init_ram_device_ptr(MemoryRegion *mr, Object *owner,
const char *name, uint64_t size,
void *ptr)
{
- memory_region_init_io(mr, owner, &ram_device_mem_ops, mr, name, size);
- mr->ram = true;
+ memory_region_init_ram_ptr(mr, owner, name, size, ptr);
mr->ram_device = true;
- memory_region_set_ram_ptr(mr, size, ptr);
}
void memory_region_init_alias(MemoryRegion *mr, Object *owner,
diff --git a/system/trace-events b/system/trace-events
index 51b4a4679a..d483b31419 100644
--- a/system/trace-events
+++ b/system/trace-events
@@ -20,8 +20,6 @@ memory_region_ops_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, u
memory_region_ops_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size, const char *name) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u name '%s'"
memory_region_subpage_read(int cpu_index, void *mr, uint64_t offset, uint64_t value, unsigned size) "cpu %d mr %p offset 0x%"PRIx64" value 0x%"PRIx64" size %u"
memory_region_subpage_write(int cpu_index, void *mr, uint64_t offset, uint64_t value, unsigned size) "cpu %d mr %p offset 0x%"PRIx64" value 0x%"PRIx64" size %u"
-memory_region_ram_device_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
-memory_region_ram_device_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
memory_region_sync_dirty(const char *mr, const char *listener, int global) "mr '%s' listener '%s' synced (global=%d)"
flatview_new(void *view, void *root) "%p (root %p)"
flatview_destroy(void *view, void *root) "%p (root %p)"
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PULL 06/10] tests/qtest/migration: Only build tls_no_hostname test with TASN1
2026-08-12 15:14 [PULL 00/10] Next patches Peter Xu
` (4 preceding siblings ...)
2026-08-12 15:14 ` [PULL 05/10] system/memory: Make ram device region directly accessible Peter Xu
@ 2026-08-12 15:14 ` Peter Xu
2026-08-12 15:14 ` [PULL 07/10] migration/multifd: Validate next_packet_size in zlib/zstd recv Peter Xu
` (4 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Peter Xu @ 2026-08-12 15:14 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Xu, Fabiano Rosas, Paolo Bonzini, Sam Heney
From: Sam Heney <github@me.samiser.xyz>
The test_precopy_tcp_tls_no_hostname test and its start hook use
TestMigrateTLSX509 and migrate_hook_start_tls_x509_common(), which
are only defined when CONFIG_TASN1 is set. This means building with
gnutls enabled but libtasn1 unavailable fails:
../tests/qtest/migration/tls-tests.c: In function 'migrate_hook_start_tls_x509_no_host':
../tests/qtest/migration/tls-tests.c:510:5: error: unknown type name 'TestMigrateTLSX509'
Guard the test with CONFIG_TASN1 like the other x509 tests.
Fixes: df9c38b19af8 ("tests/qtest/migration: Add a NULL parameters test for TLS")
Signed-off-by: Sam Heney <github@me.samiser.xyz>
Link: https://lore.kernel.org/r/5f24de0e-49af-45a7-927f-f79b203bb335@app.fastmail.com
Signed-off-by: Peter Xu <peterx@redhat.com>
---
tests/qtest/migration/tls-tests.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index 827cc7bcf8..9bdb1165af 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -492,6 +492,7 @@ static void test_precopy_tcp_no_tls(char *name, MigrateCommon *args)
test_precopy_common(args);
}
+#ifdef CONFIG_TASN1
static void *
migrate_hook_start_tls_x509_no_host(QTestState *from, QTestState *to)
{
@@ -519,7 +520,6 @@ static void test_precopy_tcp_tls_no_hostname(char *name, MigrateCommon *args)
test_precopy_common(args);
}
-#ifdef CONFIG_TASN1
static void test_precopy_tcp_tls_x509_default_host(char *name,
MigrateCommon *args)
{
@@ -719,8 +719,10 @@ void migration_test_add_tls(MigrationTestEnv *env)
migration_test_add("/migration/precopy/tcp/no-tls",
test_precopy_tcp_no_tls);
+#ifdef CONFIG_TASN1
migration_test_add("/migration/precopy/tcp/tls/no-hostname",
test_precopy_tcp_tls_no_hostname);
+#endif /* CONFIG_TASN1 */
migration_test_add("/migration/precopy/unix/tls/psk",
test_precopy_unix_tls_psk);
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PULL 07/10] migration/multifd: Validate next_packet_size in zlib/zstd recv
2026-08-12 15:14 [PULL 00/10] Next patches Peter Xu
` (5 preceding siblings ...)
2026-08-12 15:14 ` [PULL 06/10] tests/qtest/migration: Only build tls_no_hostname test with TASN1 Peter Xu
@ 2026-08-12 15:14 ` Peter Xu
2026-08-12 15:14 ` [PULL 08/10] migration/multifd: Replace assert() with error_setg() in recv paths Peter Xu
` (3 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Peter Xu @ 2026-08-12 15:14 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Fabiano Rosas, Paolo Bonzini, xlabai, Jules Denardou,
Tristan Madani, qemu-stable
The zlib and zstd multifd compression backends read next_packet_size from
the incoming migration stream and use it directly as the read length into a
fixed-size buffer (MULTIFD_PACKET_SIZE * 2 = 1MB). A malicious migration
source can set next_packet_size bigger than allocated, causing a heap
buffer overflow write on the destination.
Add a check against zbuff_len before reading, matching what the qatzip
backend already does. Also replace the assert(in_size == 0) for empty
packets with proper error reporting, since the value is wire-controlled,
meanwhile assert() stops working with -DNDEBUG builds.
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3737
Reported-by: xlabai <xlabai@tencent.com>
Reported-by: Jules Denardou <jules.denardou@datadoghq.com>
Reported-by: Tristan Madani <tristan@talencesecurity.com>
Reported-by: david korczynski (@david1766)
Reported-by: huntr bubble (@bubblehuntr)
Cc: qemu-stable <qemu-stable@nongnu.org>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Link: https://lore.kernel.org/r/20260728210417.1925078-3-peterx@redhat.com
Signed-off-by: Peter Xu <peterx@redhat.com>
---
migration/multifd-zlib.c | 11 ++++++++++-
migration/multifd-zstd.c | 11 ++++++++++-
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c
index 8820b2a787..400146566e 100644
--- a/migration/multifd-zlib.c
+++ b/migration/multifd-zlib.c
@@ -216,10 +216,19 @@ static int multifd_zlib_recv(MultiFDRecvParams *p, Error **errp)
return -1;
}
+ if (in_size > z->zbuff_len) {
+ error_setg(errp, "multifd %u: next_packet_size %"PRIu32
+ " exceeds allocated %"PRIu32, p->id, in_size, z->zbuff_len);
+ return -1;
+ }
+
multifd_recv_zero_page_process(p);
if (!p->normal_num) {
- assert(in_size == 0);
+ if (in_size != 0) {
+ error_setg(errp, "multifd %u: expected empty packet", p->id);
+ return -1;
+ }
return 0;
}
diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c
index 3c2dcf76b0..69ef1a5f38 100644
--- a/migration/multifd-zstd.c
+++ b/migration/multifd-zstd.c
@@ -210,10 +210,19 @@ static int multifd_zstd_recv(MultiFDRecvParams *p, Error **errp)
return -1;
}
+ if (in_size > z->zbuff_len) {
+ error_setg(errp, "multifd %u: next_packet_size %"PRIu32
+ " exceeds allocated %"PRIu32, p->id, in_size, z->zbuff_len);
+ return -1;
+ }
+
multifd_recv_zero_page_process(p);
if (!p->normal_num) {
- assert(in_size == 0);
+ if (in_size != 0) {
+ error_setg(errp, "multifd %u: expected empty packet", p->id);
+ return -1;
+ }
return 0;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PULL 08/10] migration/multifd: Replace assert() with error_setg() in recv paths
2026-08-12 15:14 [PULL 00/10] Next patches Peter Xu
` (6 preceding siblings ...)
2026-08-12 15:14 ` [PULL 07/10] migration/multifd: Validate next_packet_size in zlib/zstd recv Peter Xu
@ 2026-08-12 15:14 ` Peter Xu
2026-08-12 15:14 ` [PULL 09/10] migration/ram: Check for RAMBlock size mismatch when parsing Peter Xu
` (2 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Peter Xu @ 2026-08-12 15:14 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Fabiano Rosas, Paolo Bonzini, qemu-stable, Yuan Liu,
Yichen Wang
QPL and UADK multifd backends use assert() to validate wire-controlled
fields like per-page compressed lengths and packet size consistency. These
asserts will stop working with -DNDEBUG builds, so may stop working.
Replace all assert() calls in the receive path with proper error_setg() so
validation failures are reported gracefully rather than crashing or
silently ignored.
While at it, touch up an assert() in qatzip recv path too.
Cc: qemu-stable <qemu-stable@nongnu.org>
Cc: Yuan Liu <yuan1.liu@intel.com>
Cc: Yichen Wang <yichen.wang@bytedance.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Link: https://lore.kernel.org/r/20260728210417.1925078-4-peterx@redhat.com
Signed-off-by: Peter Xu <peterx@redhat.com>
---
migration/multifd-qatzip.c | 5 ++++-
migration/multifd-qpl.c | 24 ++++++++++++++++++++----
migration/multifd-uadk.c | 24 ++++++++++++++++++++----
3 files changed, 44 insertions(+), 9 deletions(-)
diff --git a/migration/multifd-qatzip.c b/migration/multifd-qatzip.c
index 7419e5dc0d..0262e81eac 100644
--- a/migration/multifd-qatzip.c
+++ b/migration/multifd-qatzip.c
@@ -348,7 +348,10 @@ static int qatzip_recv(MultiFDRecvParams *p, Error **errp)
multifd_recv_zero_page_process(p);
if (!p->normal_num) {
- assert(in_size == 0);
+ if (in_size != 0) {
+ error_setg(errp, "multifd %u: expected empty packet", p->id);
+ return -1;
+ }
return 0;
}
diff --git a/migration/multifd-qpl.c b/migration/multifd-qpl.c
index 52902eb00c..3826e7f340 100644
--- a/migration/multifd-qpl.c
+++ b/migration/multifd-qpl.c
@@ -664,26 +664,42 @@ static int multifd_qpl_recv(MultiFDRecvParams *p, Error **errp)
}
multifd_recv_zero_page_process(p);
if (!p->normal_num) {
- assert(in_size == 0);
+ if (in_size != 0) {
+ error_setg(errp, "multifd %u: expected empty packet", p->id);
+ return -1;
+ }
return 0;
}
/* read compressed page lengths */
len = p->normal_num * sizeof(uint32_t);
- assert(len < in_size);
+ if (len >= in_size) {
+ error_setg(errp, "multifd %u: header len %"PRIu32
+ " >= packet size %"PRIu32, p->id, len, in_size);
+ return -1;
+ }
ret = qio_channel_read_all(p->c, (void *) qpl->zlen, len, errp);
if (ret != 0) {
return ret;
}
for (int i = 0; i < p->normal_num; i++) {
qpl->zlen[i] = be32_to_cpu(qpl->zlen[i]);
- assert(qpl->zlen[i] <= multifd_ram_page_size());
+ if (qpl->zlen[i] > multifd_ram_page_size()) {
+ error_setg(errp, "multifd %u: page %d compressed len %"
+ PRIu32" too large", p->id, i, qpl->zlen[i]);
+ return -1;
+ }
zbuf_len += qpl->zlen[i];
ramblock_recv_bitmap_set_offset(p->block, p->normal[i]);
}
/* read compressed pages */
- assert(in_size == len + zbuf_len);
+ if (in_size != len + zbuf_len) {
+ error_setg(errp, "multifd %u: packet size %"PRIu32
+ " != header %"PRIu32" + data %"PRIu32,
+ p->id, in_size, len, zbuf_len);
+ return -1;
+ }
ret = qio_channel_read_all(p->c, (void *) qpl->zbuf, zbuf_len, errp);
if (ret != 0) {
return ret;
diff --git a/migration/multifd-uadk.c b/migration/multifd-uadk.c
index fd7cd9b5e8..d373615ba8 100644
--- a/migration/multifd-uadk.c
+++ b/migration/multifd-uadk.c
@@ -245,12 +245,19 @@ static int multifd_uadk_recv(MultiFDRecvParams *p, Error **errp)
multifd_recv_zero_page_process(p);
if (!p->normal_num) {
- assert(in_size == 0);
+ if (in_size != 0) {
+ error_setg(errp, "multifd %u: expected empty packet", p->id);
+ return -1;
+ }
return 0;
}
/* read compressed data lengths */
- assert(hdr_len < in_size);
+ if (hdr_len >= in_size) {
+ error_setg(errp, "multifd %u: header len %"PRIu32
+ " >= packet size %"PRIu32, p->id, hdr_len, in_size);
+ return -1;
+ }
ret = qio_channel_read_all(p->c, (void *) uadk_data->buf_hdr,
hdr_len, errp);
if (ret != 0) {
@@ -259,12 +266,21 @@ static int multifd_uadk_recv(MultiFDRecvParams *p, Error **errp)
for (int i = 0; i < p->normal_num; i++) {
uadk_data->buf_hdr[i] = be32_to_cpu(uadk_data->buf_hdr[i]);
+ if (uadk_data->buf_hdr[i] > page_size) {
+ error_setg(errp, "multifd %u: page %d compressed len %"PRIu32
+ " too large", p->id, i, uadk_data->buf_hdr[i]);
+ return -1;
+ }
data_len += uadk_data->buf_hdr[i];
- assert(uadk_data->buf_hdr[i] <= page_size);
}
/* read compressed data */
- assert(in_size == hdr_len + data_len);
+ if (in_size != hdr_len + data_len) {
+ error_setg(errp, "multifd %u: packet size %"PRIu32
+ " != header %"PRIu32" + data %"PRIu32,
+ p->id, in_size, hdr_len, data_len);
+ return -1;
+ }
ret = qio_channel_read_all(p->c, (void *)buf, data_len, errp);
if (ret != 0) {
return ret;
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PULL 09/10] migration/ram: Check for RAMBlock size mismatch when parsing
2026-08-12 15:14 [PULL 00/10] Next patches Peter Xu
` (7 preceding siblings ...)
2026-08-12 15:14 ` [PULL 08/10] migration/multifd: Replace assert() with error_setg() in recv paths Peter Xu
@ 2026-08-12 15:14 ` Peter Xu
2026-08-12 15:14 ` [PULL 10/10] migration: Fix rare hang of migration_channel_read_peek() Peter Xu
2026-08-12 22:01 ` [PULL 00/10] Next patches Richard Henderson
10 siblings, 0 replies; 18+ messages in thread
From: Peter Xu @ 2026-08-12 15:14 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Xu, Fabiano Rosas, Paolo Bonzini, Tristan Madani
Add an underflow check for the subtract of total RAMBlock size to make sure
it won't underflow. It should not happen in production systems but only if
the migration stream was hijacked, which is not a real concern since
migration channel is trusted. Still protect against it.
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4013
Reported-by: Tristan Madani <tristan@talencesecurity.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Link: https://lore.kernel.org/r/20260728210417.1925078-6-peterx@redhat.com
Signed-off-by: Peter Xu <peterx@redhat.com>
---
migration/ram.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/migration/ram.c b/migration/ram.c
index 8918b2f03b..85feff578c 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -4268,7 +4268,7 @@ static int parse_ramblocks(QEMUFile *f, ram_addr_t total_ram_bytes)
int ret = 0;
/* Synchronize RAM block list */
- while (!ret && total_ram_bytes) {
+ while (total_ram_bytes) {
RAMBlock *block;
char id[256];
ram_addr_t length;
@@ -4285,8 +4285,15 @@ static int parse_ramblocks(QEMUFile *f, ram_addr_t total_ram_bytes)
error_report("Unknown ramblock \"%s\", cannot accept "
"migration", id);
ret = -EINVAL;
+ break;
+ }
+
+ if (usub64_overflow(total_ram_bytes, length, &total_ram_bytes)) {
+ error_report("%s: RAMBlock '%s' size underflow total RAM size",
+ __func__, block->idstr);
+ ret = -EFAULT;
+ break;
}
- total_ram_bytes -= length;
}
return ret;
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PULL 10/10] migration: Fix rare hang of migration_channel_read_peek()
2026-08-12 15:14 [PULL 00/10] Next patches Peter Xu
` (8 preceding siblings ...)
2026-08-12 15:14 ` [PULL 09/10] migration/ram: Check for RAMBlock size mismatch when parsing Peter Xu
@ 2026-08-12 15:14 ` Peter Xu
2026-08-12 22:01 ` [PULL 00/10] Next patches Richard Henderson
10 siblings, 0 replies; 18+ messages in thread
From: Peter Xu @ 2026-08-12 15:14 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Fabiano Rosas, Paolo Bonzini, Feifan Qian,
Daniel P. Berrangé
In an unlikely case, when a migration stream is attached to the destination
QEMU and only send <4 bytes to the channel as magic, it's possible that
migration_channel_read_peek() may spin forever.
Fix it by adding a manual sleep for partial read.
Since the path isn't attached to a coroutine, it means when partial read
happens, there's yet not much we can do but hang the main thread, it will
happen even for len==0 case. It means monitors can hang due to this,
either partial read or no data arrived (but connection established).
Leave this for later, the hope is this is extremely rare in production.
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3889
Reported-by: Feifan Qian <bea1e@proton.me>
Cc: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Link: https://lore.kernel.org/r/20260812124327.2572363-1-peterx@redhat.com
Signed-off-by: Peter Xu <peterx@redhat.com>
---
migration/channel.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/migration/channel.c b/migration/channel.c
index 1e2935f926..266ae8f776 100644
--- a/migration/channel.c
+++ b/migration/channel.c
@@ -296,9 +296,16 @@ int migration_channel_read_peek(QIOChannel *ioc,
if (len == buflen) {
break;
+ } else if (len == QIO_CHANNEL_ERR_BLOCK) {
+ qio_channel_wait_cond(ioc, G_IO_IN);
+ } else {
+ /*
+ * When partially ready, we can't use qio_channel_wait_cond()
+ * because it will return immediately. Apply a manual wait.
+ */
+ assert(!qemu_in_coroutine());
+ g_usleep(1000);
}
-
- qio_channel_wait_cond(ioc, G_IO_IN);
}
return 0;
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PULL 00/10] Next patches
2026-08-12 15:14 [PULL 00/10] Next patches Peter Xu
` (9 preceding siblings ...)
2026-08-12 15:14 ` [PULL 10/10] migration: Fix rare hang of migration_channel_read_peek() Peter Xu
@ 2026-08-12 22:01 ` Richard Henderson
2026-08-13 12:38 ` Peter Xu
10 siblings, 1 reply; 18+ messages in thread
From: Richard Henderson @ 2026-08-12 22:01 UTC (permalink / raw)
To: qemu-devel
On 8/12/26 08:14, Peter Xu wrote:
> The following changes since commit 84f07211cc5b4fc6a371559bf8a5de4fb068e648:
>
> Update version for v11.1.0 release (2026-08-11 10:04:46 -0400)
>
> are available in the Git repository at:
>
> https://gitlab.com/peterx/qemu.git tags/next-pull-request
>
> for you to fetch changes up to 2375e9b1239eb6ad794eaae29245b94f429c87c5:
>
> migration: Fix rare hang of migration_channel_read_peek() (2026-08-12 10:42:09 -0400)
>
> ----------------------------------------------------------------
> migration/mem pull for 11.2
>
> next 11.2:
> - Dongli's patch to add cpr-transfer support for HMP
> - Fabiano's doc update for migration on security issues
> - Gavin's fix for MMIO access support for memory APIs, reverting ram_device ops
> - Sam's migration test build fix for !ASN1
> - Peter's a few migration hardening fixes
MacOS build failures:
https://gitlab.com/qemu-project/qemu/-/jobs/15865084063
https://gitlab.com/qemu-project/qemu/-/jobs/15865084064
../migration/ram.c:4291:54: error: incompatible pointer types passing 'ram_addr_t *' (aka
'unsigned long *') to parameter of type 'uint64_t *' (aka 'unsigned long long *')
[-Werror,-Wincompatible-pointer-types]
4291 | if (usub64_overflow(total_ram_bytes, length, &total_ram_bytes)) {
| ^~~~~~~~~~~~~~~~
/Users/gitlab/builds/qemu-project/qemu/include/qemu/host-utils.h:552:70: note: passing
argument to parameter 'ret' here
552 | static inline bool usub64_overflow(uint64_t x, uint64_t y, uint64_t *ret)
| ^
Note that ram_addr_t maps to uintptr_t not uint64_t.
Which should be functionally the same, but is probably
an 'unsigned long' vs 'unsigned long long' mismatch.
Perhaps we should just be using __builtin_add_overflow via a macro instead of inlines so
that we get the full functionality of the types accepted by the builtin.
r~
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PULL 00/10] Next patches
2026-08-12 22:01 ` [PULL 00/10] Next patches Richard Henderson
@ 2026-08-13 12:38 ` Peter Xu
2026-08-13 13:41 ` Peter Xu
0 siblings, 1 reply; 18+ messages in thread
From: Peter Xu @ 2026-08-13 12:38 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel
On Wed, Aug 12, 2026 at 03:01:14PM -0700, Richard Henderson wrote:
> On 8/12/26 08:14, Peter Xu wrote:
> > The following changes since commit 84f07211cc5b4fc6a371559bf8a5de4fb068e648:
> >
> > Update version for v11.1.0 release (2026-08-11 10:04:46 -0400)
> >
> > are available in the Git repository at:
> >
> > https://gitlab.com/peterx/qemu.git tags/next-pull-request
> >
> > for you to fetch changes up to 2375e9b1239eb6ad794eaae29245b94f429c87c5:
> >
> > migration: Fix rare hang of migration_channel_read_peek() (2026-08-12 10:42:09 -0400)
> >
> > ----------------------------------------------------------------
> > migration/mem pull for 11.2
> >
> > next 11.2:
> > - Dongli's patch to add cpr-transfer support for HMP
> > - Fabiano's doc update for migration on security issues
> > - Gavin's fix for MMIO access support for memory APIs, reverting ram_device ops
> > - Sam's migration test build fix for !ASN1
> > - Peter's a few migration hardening fixes
>
> MacOS build failures:
>
> https://gitlab.com/qemu-project/qemu/-/jobs/15865084063
> https://gitlab.com/qemu-project/qemu/-/jobs/15865084064
>
> ../migration/ram.c:4291:54: error: incompatible pointer types passing
> 'ram_addr_t *' (aka 'unsigned long *') to parameter of type 'uint64_t *'
> (aka 'unsigned long long *') [-Werror,-Wincompatible-pointer-types]
> 4291 | if (usub64_overflow(total_ram_bytes, length, &total_ram_bytes)) {
> | ^~~~~~~~~~~~~~~~
> /Users/gitlab/builds/qemu-project/qemu/include/qemu/host-utils.h:552:70:
> note: passing argument to parameter 'ret' here
> 552 | static inline bool usub64_overflow(uint64_t x, uint64_t y, uint64_t *ret)
> | ^
>
> Note that ram_addr_t maps to uintptr_t not uint64_t.
> Which should be functionally the same, but is probably
> an 'unsigned long' vs 'unsigned long long' mismatch.
>
> Perhaps we should just be using __builtin_add_overflow via a macro instead
> of inlines so that we get the full functionality of the types accepted by
> the builtin.
Ohhh I almost missed this email... somehow it lost all CCs include myself.
I'll see how to fix and repost, thanks for the hints!
--
Peter Xu
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PULL 00/10] Next patches
2026-08-13 12:38 ` Peter Xu
@ 2026-08-13 13:41 ` Peter Xu
2026-08-13 14:14 ` Richard Henderson
0 siblings, 1 reply; 18+ messages in thread
From: Peter Xu @ 2026-08-13 13:41 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel, Paolo Bonzini, Fabiano Rosas
On Thu, Aug 13, 2026 at 08:38:38AM -0400, Peter Xu wrote:
> On Wed, Aug 12, 2026 at 03:01:14PM -0700, Richard Henderson wrote:
> > On 8/12/26 08:14, Peter Xu wrote:
> > > The following changes since commit 84f07211cc5b4fc6a371559bf8a5de4fb068e648:
> > >
> > > Update version for v11.1.0 release (2026-08-11 10:04:46 -0400)
> > >
> > > are available in the Git repository at:
> > >
> > > https://gitlab.com/peterx/qemu.git tags/next-pull-request
> > >
> > > for you to fetch changes up to 2375e9b1239eb6ad794eaae29245b94f429c87c5:
> > >
> > > migration: Fix rare hang of migration_channel_read_peek() (2026-08-12 10:42:09 -0400)
> > >
> > > ----------------------------------------------------------------
> > > migration/mem pull for 11.2
> > >
> > > next 11.2:
> > > - Dongli's patch to add cpr-transfer support for HMP
> > > - Fabiano's doc update for migration on security issues
> > > - Gavin's fix for MMIO access support for memory APIs, reverting ram_device ops
> > > - Sam's migration test build fix for !ASN1
> > > - Peter's a few migration hardening fixes
> >
> > MacOS build failures:
> >
> > https://gitlab.com/qemu-project/qemu/-/jobs/15865084063
> > https://gitlab.com/qemu-project/qemu/-/jobs/15865084064
> >
> > ../migration/ram.c:4291:54: error: incompatible pointer types passing
> > 'ram_addr_t *' (aka 'unsigned long *') to parameter of type 'uint64_t *'
> > (aka 'unsigned long long *') [-Werror,-Wincompatible-pointer-types]
> > 4291 | if (usub64_overflow(total_ram_bytes, length, &total_ram_bytes)) {
> > | ^~~~~~~~~~~~~~~~
> > /Users/gitlab/builds/qemu-project/qemu/include/qemu/host-utils.h:552:70:
> > note: passing argument to parameter 'ret' here
> > 552 | static inline bool usub64_overflow(uint64_t x, uint64_t y, uint64_t *ret)
> > | ^
> >
> > Note that ram_addr_t maps to uintptr_t not uint64_t.
> > Which should be functionally the same, but is probably
> > an 'unsigned long' vs 'unsigned long long' mismatch.
> >
> > Perhaps we should just be using __builtin_add_overflow via a macro instead
> > of inlines so that we get the full functionality of the types accepted by
> > the builtin.
>
> Ohhh I almost missed this email... somehow it lost all CCs include myself.
> I'll see how to fix and repost, thanks for the hints!
So for this one I plan to squash this (will repost in a minute):
diff --git a/migration/ram.c b/migration/ram.c
index 85feff578c..b6eb842746 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -4263,7 +4263,7 @@ static int parse_ramblock(QEMUFile *f, RAMBlock *block, ram_addr_t length)
return ret;
}
-static int parse_ramblocks(QEMUFile *f, ram_addr_t total_ram_bytes)
+static int parse_ramblocks(QEMUFile *f, uint64_t total_ram_bytes)
{
int ret = 0;
@@ -4271,7 +4271,7 @@ static int parse_ramblocks(QEMUFile *f, ram_addr_t total_ram_bytes)
while (total_ram_bytes) {
RAMBlock *block;
char id[256];
- ram_addr_t length;
+ uint64_t length;
int len = qemu_get_byte(f);
qemu_get_buffer(f, (uint8_t *)id, len);
After all, whole migration treats ram_addr_t to be u64, at least on wire.
For the long term, do we want to fully expose __builtin_add_overflow(), or
the new macro would do something more than what __builtin_add_overflow()
does?
Now when I think about it from the root, I tend to like what Xen defines
with ram_addr_t:
/* address in the RAM (different from a physical address) */
#if defined(CONFIG_XEN_BACKEND)
typedef uint64_t ram_addr_t;
# define RAM_ADDR_MAX UINT64_MAX
# define RAM_ADDR_FMT "%" PRIx64
#else
typedef uintptr_t ram_addr_t;
# define RAM_ADDR_MAX UINTPTR_MAX
# define RAM_ADDR_FMT "%" PRIxPTR
#endif
I don't know how we supported 32bit host emulating anything larger, but
logically it's doable, then IIUC uintptr_t won't be enough allocating
anything >4G? If emulating 64bits is too much, I still think it seems valid
to emulate e.g. PAE 36bits on a 32bit. I didn't check how it was done now
or before, but logically it sounds that it should still work.
Meanwhile, we should never directly use a ram_addr_t* to be a pointer - it
simply is not, but only the address space qemu uses internally for
ramblocks. That also implies to me that this seems to be a bit off.
Thanks,
--
Peter Xu
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PULL 00/10] Next patches
2026-08-13 13:41 ` Peter Xu
@ 2026-08-13 14:14 ` Richard Henderson
2026-08-13 14:51 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 18+ messages in thread
From: Richard Henderson @ 2026-08-13 14:14 UTC (permalink / raw)
To: Peter Xu; +Cc: qemu-devel, Paolo Bonzini, Fabiano Rosas
On 8/13/26 06:41, Peter Xu wrote:
> Now when I think about it from the root, I tend to like what Xen defines
> with ram_addr_t:
>
> /* address in the RAM (different from a physical address) */
> #if defined(CONFIG_XEN_BACKEND)
> typedef uint64_t ram_addr_t;
> # define RAM_ADDR_MAX UINT64_MAX
> # define RAM_ADDR_FMT "%" PRIx64
> #else
> typedef uintptr_t ram_addr_t;
> # define RAM_ADDR_MAX UINTPTR_MAX
> # define RAM_ADDR_FMT "%" PRIxPTR
> #endif
>
> I don't know how we supported 32bit host emulating anything larger, but
> logically it's doable, then IIUC uintptr_t won't be enough allocating
> anything >4G?
ram_addr_t != hwaddr or vaddr -- it's just an internal token.
So a 32-bit machine could put 1G of ram (identified by ram_addr_t) at 8G (hwaddr) just
fine. But obviously it couldn't put 8G of ram anywhere. :-)
That said, Xen was weird in that it used to be possible to have an i386 qemu command-line
talking to a x86_64 dom0 kernel controlling x86_64 guests.
So, yeah, now we should drop this ram_addr_t distinction and always use uint64_t.
r~
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PULL 00/10] Next patches
2026-08-13 14:14 ` Richard Henderson
@ 2026-08-13 14:51 ` Philippe Mathieu-Daudé
2026-08-13 15:05 ` Peter Xu
0 siblings, 1 reply; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-13 14:51 UTC (permalink / raw)
To: Richard Henderson, Peter Xu; +Cc: qemu-devel, Paolo Bonzini, Fabiano Rosas
On 13/8/26 16:14, Richard Henderson wrote:
> On 8/13/26 06:41, Peter Xu wrote:
>> Now when I think about it from the root, I tend to like what Xen defines
>> with ram_addr_t:
>>
>> /* address in the RAM (different from a physical address) */
>> #if defined(CONFIG_XEN_BACKEND)
>> typedef uint64_t ram_addr_t;
>> # define RAM_ADDR_MAX UINT64_MAX
>> # define RAM_ADDR_FMT "%" PRIx64
>> #else
>> typedef uintptr_t ram_addr_t;
>> # define RAM_ADDR_MAX UINTPTR_MAX
>> # define RAM_ADDR_FMT "%" PRIxPTR
>> #endif
>>
>> I don't know how we supported 32bit host emulating anything larger, but
>> logically it's doable, then IIUC uintptr_t won't be enough allocating
>> anything >4G?
>
> ram_addr_t != hwaddr or vaddr -- it's just an internal token.
>
> So a 32-bit machine could put 1G of ram (identified by ram_addr_t) at 8G
> (hwaddr) just fine. But obviously it couldn't put 8G of ram anywhere. :-)
>
> That said, Xen was weird in that it used to be possible to have an i386
> qemu command-line talking to a x86_64 dom0 kernel controlling x86_64
> guests.
>
> So, yeah, now we should drop this ram_addr_t distinction and always use
> uint64_t.
🩷🩷🩷 lovely 🩷🩷🩷
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PULL 00/10] Next patches
2026-08-13 14:51 ` Philippe Mathieu-Daudé
@ 2026-08-13 15:05 ` Peter Xu
2026-08-13 15:18 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 18+ messages in thread
From: Peter Xu @ 2026-08-13 15:05 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Richard Henderson, qemu-devel, Paolo Bonzini, Fabiano Rosas
On Thu, Aug 13, 2026 at 04:51:39PM +0200, Philippe Mathieu-Daudé wrote:
> On 13/8/26 16:14, Richard Henderson wrote:
> > On 8/13/26 06:41, Peter Xu wrote:
> > > Now when I think about it from the root, I tend to like what Xen defines
> > > with ram_addr_t:
> > >
> > > /* address in the RAM (different from a physical address) */
> > > #if defined(CONFIG_XEN_BACKEND)
> > > typedef uint64_t ram_addr_t;
> > > # define RAM_ADDR_MAX UINT64_MAX
> > > # define RAM_ADDR_FMT "%" PRIx64
> > > #else
> > > typedef uintptr_t ram_addr_t;
> > > # define RAM_ADDR_MAX UINTPTR_MAX
> > > # define RAM_ADDR_FMT "%" PRIxPTR
> > > #endif
> > >
> > > I don't know how we supported 32bit host emulating anything larger, but
> > > logically it's doable, then IIUC uintptr_t won't be enough allocating
> > > anything >4G?
> >
> > ram_addr_t != hwaddr or vaddr -- it's just an internal token.
> >
> > So a 32-bit machine could put 1G of ram (identified by ram_addr_t) at 8G
> > (hwaddr) just fine. But obviously it couldn't put 8G of ram anywhere.
> > :-)
Yep, I should have described it as allocating >4G in total, rather in one
shot. So it's about the address space we can allocate that is limited..
> >
> > That said, Xen was weird in that it used to be possible to have an i386
> > qemu command-line talking to a x86_64 dom0 kernel controlling x86_64
> > guests.
> >
> > So, yeah, now we should drop this ram_addr_t distinction and always use
> > uint64_t.
>
> 🩷🩷🩷 lovely 🩷🩷🩷
I can throw a patch, just to double check one last thing: we don't support
any form of 32bit hosts anymore, am I right?
--
Peter Xu
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PULL 00/10] Next patches
2026-08-13 15:05 ` Peter Xu
@ 2026-08-13 15:18 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-13 15:18 UTC (permalink / raw)
To: Peter Xu; +Cc: Richard Henderson, qemu-devel, Paolo Bonzini, Fabiano Rosas
On 13/8/26 17:05, Peter Xu wrote:
> On Thu, Aug 13, 2026 at 04:51:39PM +0200, Philippe Mathieu-Daudé wrote:
>> On 13/8/26 16:14, Richard Henderson wrote:
>>> On 8/13/26 06:41, Peter Xu wrote:
>>>> Now when I think about it from the root, I tend to like what Xen defines
>>>> with ram_addr_t:
>>>>
>>>> /* address in the RAM (different from a physical address) */
>>>> #if defined(CONFIG_XEN_BACKEND)
>>>> typedef uint64_t ram_addr_t;
>>>> # define RAM_ADDR_MAX UINT64_MAX
>>>> # define RAM_ADDR_FMT "%" PRIx64
>>>> #else
>>>> typedef uintptr_t ram_addr_t;
>>>> # define RAM_ADDR_MAX UINTPTR_MAX
>>>> # define RAM_ADDR_FMT "%" PRIxPTR
>>>> #endif
>>>>
>>>> I don't know how we supported 32bit host emulating anything larger, but
>>>> logically it's doable, then IIUC uintptr_t won't be enough allocating
>>>> anything >4G?
>>>
>>> ram_addr_t != hwaddr or vaddr -- it's just an internal token.
>>>
>>> So a 32-bit machine could put 1G of ram (identified by ram_addr_t) at 8G
>>> (hwaddr) just fine. But obviously it couldn't put 8G of ram anywhere.
>>> :-)
>
> Yep, I should have described it as allocating >4G in total, rather in one
> shot. So it's about the address space we can allocate that is limited..
>
>>>
>>> That said, Xen was weird in that it used to be possible to have an i386
>>> qemu command-line talking to a x86_64 dom0 kernel controlling x86_64
>>> guests.
>>>
>>> So, yeah, now we should drop this ram_addr_t distinction and always use
>>> uint64_t.
>>
>> 🩷🩷🩷 lovely 🩷🩷🩷
>
> I can throw a patch, just to double check one last thing: we don't support
> any form of 32bit hosts anymore, am I right?
commit 372ec46b9f1215f48a4717f2b7ed969f65bfadc6
Author: Richard Henderson <richard.henderson@linaro.org>
Date: Thu Dec 18 09:56:27 2025 +1100
meson: Reject 32-bit hosts
32-bit hosts have been deprecated since 10.0.
diff --git a/docs/about/removed-features.rst
b/docs/about/removed-features.rst
+32-bit host operating systems (removed in 11.0)
+'''''''''''''''''''''''''''''''''''''''''''''''
^ permalink raw reply [flat|nested] 18+ messages in thread