Commit cf45083edc for qemu.org
commit cf45083edc2b760a952836187aba7ec4139418c0
Author: Peter Xu <peterx@redhat.com>
Date: Tue Jul 28 17:04:15 2026 -0400
migration/multifd: Replace assert() with error_setg() in recv paths
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>
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;