From: Dave Voutila Subject: Re: vmd: rewind ibuf on forward To: Nick Owens Cc: tech@openbsd.org Date: Thu, 03 Sep 2026 12:35:17 -0400 Nick Owens writes: > unlike libutil's imsg, vmd's proc_forward_imsg does not rewind. if a > caller consumed it, then the forwarded message will appear to be empty. > > for me, this fixes > > vmd: control: vmop_result_read: Bad message > > which happens during IMSG_VMDOP_TERMINATE_VM_RESPONSE handling on vm > shutdown, when doing lots of concurrent vm starts/stops, in the > particular case of where a vm might have exited itself before vmd has > seen it. > This appears to be a consequence of switching vmd over to the new imsg API to consume the buffer instead of reading it directly like vmd did previously. > i don't think imsg_forward can be used here because proc_forward_imsg > can change the peer, which control.c uses, and it forwards the fd, which > imsg_forward drops. I have a counter proposal below that doesn't use ibuf_rewind(3) and ibuf_skip(3). I want to avoid touching ibufs directly. Instead lets just remove the usage of proc_forward_imsg() from the one case that causes this issue and instead compse a new imsg. > > diff --git a/usr.sbin/vmd/proc.c b/usr.sbin/vmd/proc.c > index bcc85ac4630..9e123306624 100644 > --- a/usr.sbin/vmd/proc.c > +++ b/usr.sbin/vmd/proc.c > @@ -632,6 +632,14 @@ proc_forward_imsg(struct privsep *ps, struct imsg *imsg, enum privsep_procid id, > void *data = NULL; > > fd = imsg_get_fd(imsg); > + > + /* rewind before forwarding, as imsg_forward(3) does: a getter > + * may already have consumed this imsg. > + */ > + ibuf_rewind(imsg->buf); > + if (ibuf_skip(imsg->buf, sizeof(imsg->hdr)) == -1) > + return (EINVAL); > + > sz = imsg_get_len(imsg); > type = imsg_get_type(imsg); > diff refs/heads/master refs/heads/vmd-rewind commit - 805f38d58fcea0569f8a0d41d85fdc0922c0fda0 commit + 8cf7f3405b547f64d480ef357a2d9178954841e6 blob - ee54ad31f8fc38111dc30efcea56cdfdea792bc6 blob + 240d5b5dad79abb2a859fdba6a1ddb9a2331de5d --- usr.sbin/vmd/vmd.c +++ usr.sbin/vmd/vmd.c @@ -373,7 +373,8 @@ vmd_dispatch_vmm(int fd, struct privsep_proc *p, struc if (vmr.vmr_result) { DPRINTF("%s: forwarding TERMINATE VM for vm id %d", __func__, vmr.vmr_id); - proc_forward_imsg(ps, imsg, PROC_CONTROL, -1); + proc_compose_imsg(ps, PROC_CONTROL, type, peer_id, -1, + &vmr, sizeof(vmr)); } else { if ((vm = vm_getbyvmid(vmr.vmr_id)) == NULL) break;