In postcopy mode QEMU signals that it has collected all the postcopy client
bases by sending a VHOST_USER_ADD_MEM_REG message with a u64 payload of 0
and no file descriptor (see vhost_user_add_remove_regions()).
vu_add_mem_reg() has a case for that message, but only reaches it after
validating the fd count of a regular region, so the ack is rejected first:
VHOST_USER_ADD_MEM_REG received 0 fds - only 1 fd should be sent for
this message type
This kills the backend during memory table setup, making postcopy unusable
for any libvhost-user backend that negotiates
VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS.
Recognise the ack before validating the fd count.
Fixes: 9f4e63491b ("libvhost-user: Add vu_add_mem_reg input validation")
Signed-off-by: Bin Guo <[email protected]>
---
subprojects/libvhost-user/libvhost-user.c | 26 ++++++++++++-----------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/subprojects/libvhost-user/libvhost-user.c
b/subprojects/libvhost-user/libvhost-user.c
index a74d814bb4..248550aae1 100644
--- a/subprojects/libvhost-user/libvhost-user.c
+++ b/subprojects/libvhost-user/libvhost-user.c
@@ -948,6 +948,20 @@ static bool
vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m;
+ /*
+ * If we are in postcopy mode and we receive a u64 payload with a 0 value
+ * we know all the postcopy client bases have been received, and we
+ * should start generating faults. This message carries no file
+ * descriptor, so it has to be recognised before the fd count of a real
+ * region is validated below.
+ */
+ if (dev->postcopy_listening &&
+ vmsg->size == sizeof(vmsg->payload.u64) &&
+ vmsg->payload.u64 == 0) {
+ (void)generate_faults(dev);
+ return false;
+ }
+
if (vmsg->fd_num != 1) {
vmsg_close_fds(vmsg);
vu_panic(dev, "VHOST_USER_ADD_MEM_REG received %d fds - only 1 fd "
@@ -971,18 +985,6 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
return false;
}
- /*
- * If we are in postcopy mode and we receive a u64 payload with a 0 value
- * we know all the postcopy client bases have been received, and we
- * should start generating faults.
- */
- if (dev->postcopy_listening &&
- vmsg->size == sizeof(vmsg->payload.u64) &&
- vmsg->payload.u64 == 0) {
- (void)generate_faults(dev);
- return false;
- }
-
_vu_add_mem_reg(dev, msg_region, vmsg->fds[0]);
close(vmsg->fds[0]);
--
2.50.1 (Apple Git-155)