Commit ac7fa2e9d4 for qemu.org
commit ac7fa2e9d457ff9c777be32617f3c46548c4cadf
Author: Peter Xu <peterx@redhat.com>
Date: Tue Jul 28 17:04:14 2026 -0400
migration/multifd: Validate next_packet_size in zlib/zstd recv
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>
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;
}