untrusted comment: verify with openbsd-79-base.pub RWTSdNN9A3yvWJCwIekQJsPXSmniZaMO1i+MAv3h5w2JPmJBkNj+JE3U+7EO/CbYgVsYfEzir99CnOFVW1q2KSNpSzQZ0KdG4QE= OpenBSD 7.9 errata 003, June 2, 2026: In vmd(8), fix a variety of crashing bugs and misbehavior of -b flag. Apply by doing: signify -Vep /etc/signify/openbsd-79-base.pub -x 003_vmd.patch.sig \ -m - | (cd /usr/src && patch -p0) And then rebuild and install vmd: cd /usr/src/usr.sbin/vmd make obj make make install Index: usr.sbin/vmd/config.c =================================================================== RCS file: /cvs/src/usr.sbin/vmd/config.c,v diff -u -p -r1.82 config.c --- usr.sbin/vmd/config.c 27 Apr 2026 13:06:14 -0000 1.82 +++ usr.sbin/vmd/config.c 29 May 2026 17:11:54 -0000 @@ -297,11 +297,9 @@ config_setvm(struct privsep *ps, struct goto fail; } - if ((vm->vm_kernel = dup(kernfd)) == -1) { - ret = errno; - goto fail; - } - vmc->vmc_kernel = vm->vm_kernel; + vm->vm_kernel = kernfd; + vmc->vmc_kernel = kernfd; + kernfd = -1; } /* Open CDROM image for child */ @@ -484,6 +482,10 @@ config_setvm(struct privsep *ps, struct /* Send VM information */ /* XXX check proc_compose_imsg return values */ + if ((kernfd = dup(vm->vm_kernel)) == -1) { + ret = errno; + goto fail; + } proc_compose_imsg(ps, PROC_VMM, IMSG_VMDOP_START_VM_REQUEST, vm->vm_vmid, kernfd, vmc, sizeof(*vmc)); @@ -530,8 +532,6 @@ config_setvm(struct privsep *ps, struct fail: log_warnx("failed to start vm %s", vmc->vmc_name); - if (vm->vm_kernel != -1) - close(vm->vm_kernel); if (kernfd != -1) close(kernfd); if (cdromfd != -1) @@ -546,6 +546,7 @@ config_setvm(struct privsep *ps, struct free(tapfds); } + /* Both vm_stop() and vm_remove() will close vm->vm_kernel. */ if (vm->vm_from_config) { vm_stop(vm, 0, __func__); } else { Index: usr.sbin/vmd/vioblk.c =================================================================== RCS file: /cvs/src/usr.sbin/vmd/vioblk.c,v diff -u -p -r1.28 vioblk.c --- usr.sbin/vmd/vioblk.c 14 Apr 2026 21:41:19 -0000 1.28 +++ usr.sbin/vmd/vioblk.c 29 May 2026 17:11:55 -0000 @@ -267,7 +267,7 @@ vioblk_notifyq(struct virtio_dev *dev, u struct vioblk_dev *vioblk = &dev->vioblk; /* Invalid queue? */ - if (vq_idx > dev->num_queues) + if (vq_idx >= dev->num_queues) return (0); vq_info = &dev->vq[vq_idx]; @@ -284,6 +284,11 @@ vioblk_notifyq(struct virtio_dev *dev, u while (idx != avail->idx) { /* Retrieve Command descriptor. */ cmd_desc_idx = avail->ring[idx & vq_info->mask]; + if (cmd_desc_idx >= vq_info->qs) { + log_warnx("%s: invalid head descriptor index", + __func__); + goto reset; + } desc = &table[cmd_desc_idx]; cmd_len = desc->len; Index: usr.sbin/vmd/vioscsi.c =================================================================== RCS file: /cvs/src/usr.sbin/vmd/vioscsi.c,v diff -u -p -r1.29 vioscsi.c --- usr.sbin/vmd/vioscsi.c 22 Feb 2026 22:54:54 -0000 1.29 +++ usr.sbin/vmd/vioscsi.c 29 May 2026 17:11:55 -0000 @@ -1501,6 +1501,11 @@ vioscsi_handle_read_10(struct virtio_dev __func__, acct->resp_desc->addr, acct->resp_desc->len, acct->resp_idx, acct->req_idx, acct->idx); + if (acct->resp_desc->len == 0) { + log_warnx("%s: zero-length read_buf descriptor", __func__); + goto free_read_10; + } + /* Check we don't read beyond read_buf boundaries. */ if (acct->resp_desc->len > info->len - chunk_offset) { log_warnx("%s: descriptor length beyond read_buf len", @@ -1516,7 +1521,7 @@ vioscsi_handle_read_10(struct virtio_dev acct->resp_desc->addr); goto free_read_10; } - chunk_offset += acct->resp_desc->len; + chunk_offset += chunk_len; } while (chunk_offset < info->len); ret = 1; @@ -2189,7 +2194,17 @@ vioscsi_notifyq(struct virtio_dev *dev, struct virtio_vq_acct acct; struct virtio_vq_info *vq_info; + if (vq_idx >= dev->num_queues) { + log_warnx("%s: invalid virtqueue index %u", __func__, vq_idx); + return (0); + } + vq_info = &dev->vq[vq_idx]; + if (!vq_info->vq_enabled) { + log_warnx("%s: virtqueue not enabled", __func__); + return (0); + } + vr = vq_info->q_hva; if (vr == NULL) fatalx("%s: null vring", __func__); Index: usr.sbin/vmd/virtio.c =================================================================== RCS file: /cvs/src/usr.sbin/vmd/virtio.c,v diff -u -p -r1.137 virtio.c --- usr.sbin/vmd/virtio.c 14 Apr 2026 21:41:19 -0000 1.137 +++ usr.sbin/vmd/virtio.c 29 May 2026 17:11:55 -0000 @@ -196,6 +196,7 @@ virtio_update_qa(struct virtio_dev *dev) { struct virtio_vq_info *vq_info = NULL; void *hva = NULL; + uint64_t availoff, usedoff, availsz, usedsz; if (dev->driver_feature & VIRTIO_F_VERSION_1) { if (dev->pci_cfg.queue_select >= dev->num_queues) { @@ -212,11 +213,41 @@ virtio_update_qa(struct virtio_dev *dev) vq_info->qs = dev->pci_cfg.queue_size; vq_info->mask = vq_info->qs - 1; + /* + * Require the available (driver) and used (device) area to be + * similar to Virtio 0.9 but support Virtio 1.x alignment. + */ + if (dev->pci_cfg.queue_avail < dev->pci_cfg.queue_desc || + dev->pci_cfg.queue_used < dev->pci_cfg.queue_desc) { + vq_info->vq_enabled = 0; + return; + } + + availoff = dev->pci_cfg.queue_avail - dev->pci_cfg.queue_desc; + usedoff = dev->pci_cfg.queue_used - dev->pci_cfg.queue_desc; + if (availoff > UINT32_MAX || usedoff > UINT32_MAX || + (usedoff & 3) != 0) { + vq_info->vq_enabled = 0; + return; + } + + availsz = sizeof(uint16_t) * (2 + vq_info->qs); + usedsz = (sizeof(uint16_t) * 2) + + (sizeof(struct vring_used_elem) * vq_info->qs); + hva = hvaddr_mem(dev->pci_cfg.queue_desc + availoff, availsz); + if (hva == NULL) { + vq_info->vq_enabled = 0; + return; + } + hva = hvaddr_mem(dev->pci_cfg.queue_desc + usedoff, usedsz); + if (hva == NULL) { + vq_info->vq_enabled = 0; + return; + } + if (vq_info->qs > 0 && vq_info->qs % 2 == 0) { - vq_info->vq_availoffset = dev->pci_cfg.queue_avail - - dev->pci_cfg.queue_desc; - vq_info->vq_usedoffset = dev->pci_cfg.queue_used - - dev->pci_cfg.queue_desc; + vq_info->vq_availoffset = availoff; + vq_info->vq_usedoffset = usedoff; vq_info->vq_enabled = (dev->pci_cfg.queue_enable == 1); } else { vq_info->vq_availoffset = 0; @@ -294,8 +325,10 @@ viornd_notifyq(struct virtio_dev *dev, u dxx = avail->ring[aidx] & vq_info->mask; sz = desc[dxx].len; - if (sz > MAXPHYS) - fatalx("viornd descriptor size too large (%zu)", sz); + if (sz > MAXPHYS) { + log_warnx("viornd descriptor size too large (%zu)", sz); + return (0); + } rnd_data = malloc(sz); if (rnd_data == NULL)