untrusted comment: verify with openbsd-80-base.pub RWSMSt0erHTctfAD/liog4KXaXHXNnJ/9F6SX4mNDForr45p8HY76TW85Qb1F9qV4P/NYsPHbOnvOBPcCOPlOVQp1FkrmSKCxQg= OpenBSD 8.0 errata 004, October 20, 2026: Multiple bugs in video(4) could lead to use-after-free and kernel memory corruption. Apply by doing: signify -Vep /etc/signify/openbsd-80-base.pub -x 004_video.patch.sig \ -m - | (cd /usr/src && patch -p0) And then rebuild and install a new kernel: KK=`sysctl -n kern.osversion | cut -d# -f1` cd /usr/src/sys/arch/`machine`/compile/$KK make obj make config make make install Index: sys/dev/video.c =================================================================== RCS file: /cvs/src/sys/dev/video.c,v diff -u -p -u -r1.61 video.c --- sys/dev/video.c 15 Apr 2025 06:44:37 -0000 1.61 +++ sys/dev/video.c 16 Oct 2026 20:57:22 -0000 @@ -394,6 +394,8 @@ videoioctl(dev_t dev, u_long cmd, caddr_ } error = (sc->hw_if->dqbuf)(sc->hw_hdl, (struct v4l2_buffer *)data); + if (error) + break; if (!atomic_load_int(&video_record_enable)) bzero(sc->sc_fbuffer_mmap + vb->m.offset, vb->length); mtx_enter(&sc->sc_mtx); @@ -463,8 +465,7 @@ videommap(dev_t dev, off_t off, int prot sc->sc_vidmode = VIDMODE_MMAP; /* store frame buffer base address for later blanking */ - if (off == 0) - sc->sc_fbuffer_mmap = p; + sc->sc_fbuffer_mmap = p - off; device_unref(&sc->dev); return (pa); @@ -472,6 +473,23 @@ videommap(dev_t dev, off_t off, int prot err: device_unref(&sc->dev); return (-1); +} + +void +video_mmap_revoke(caddr_t addr, size_t size) +{ + struct vm_page *pg; + paddr_t pa; + size_t off; + + for (off = 0; off < size; off += PAGE_SIZE) { + if (!pmap_extract(pmap_kernel(), (vaddr_t)addr + off, &pa)) + panic("video_mmap_revoke: invalid page"); + pg = PHYS_TO_VM_PAGE(pa); + if (pg == NULL) + panic("video_mmap_revoke: unmanaged page"); + pmap_page_protect(pg, PROT_NONE); + } } void Index: sys/dev/video_if.h =================================================================== RCS file: /cvs/src/sys/dev/video_if.h,v diff -u -p -u -r1.19 video_if.h --- sys/dev/video_if.h 21 Mar 2022 19:22:40 -0000 1.19 +++ sys/dev/video_if.h 16 Oct 2026 20:57:22 -0000 @@ -69,5 +69,6 @@ struct video_attach_args { struct device *video_attach_mi(const struct video_hw_if *, void *, struct device *); +void video_mmap_revoke(caddr_t, size_t); #endif /* _SYS_DEV_VIDEO_IF_H */ Index: sys/dev/usb/utvfu.c =================================================================== RCS file: /cvs/src/sys/dev/usb/utvfu.c,v diff -u -p -u -r1.23 utvfu.c --- sys/dev/usb/utvfu.c 25 Feb 2025 22:10:39 -0000 1.23 +++ sys/dev/usb/utvfu.c 16 Oct 2026 20:57:22 -0000 @@ -1411,7 +1411,7 @@ utvfu_mappage(void *v, off_t off, int pr struct utvfu_softc *sc = v; caddr_t p = NULL; - if (off < sc->sc_mmap_bufsz) { + if (sc->sc_mmap_buffer != NULL && off < sc->sc_mmap_bufsz) { if ((sc->sc_flags & UTVFU_FLAG_MMAP) == 0) sc->sc_flags |= UTVFU_FLAG_MMAP; @@ -1535,6 +1535,8 @@ void utvfu_vs_free_frame(struct utvfu_softc *sc) { struct utvfu_frame_buf *fb = &sc->sc_fb; + uint8_t *mmap_buffer; + size_t mmap_bufsz; if (fb->buf != NULL) { free(fb->buf, M_USBDEV, fb->size); @@ -1542,8 +1544,12 @@ utvfu_vs_free_frame(struct utvfu_softc * } if (sc->sc_mmap_buffer != NULL) { - free(sc->sc_mmap_buffer, M_USBDEV, sc->sc_mmap_bufsz); + mmap_buffer = sc->sc_mmap_buffer; + mmap_bufsz = sc->sc_mmap_bufsz; sc->sc_mmap_buffer = NULL; + sc->sc_mmap_bufsz = 0; + video_mmap_revoke(mmap_buffer, mmap_bufsz); + free(mmap_buffer, M_USBDEV, mmap_bufsz); memset(sc->sc_mmap, 0, sizeof(sc->sc_mmap)); } Index: sys/dev/usb/uvideo.c =================================================================== RCS file: /cvs/src/sys/dev/usb/uvideo.c,v diff -u -p -u -r1.266 uvideo.c --- sys/dev/usb/uvideo.c 2 Jun 2026 20:33:29 -0000 1.266 +++ sys/dev/usb/uvideo.c 16 Oct 2026 20:57:22 -0000 @@ -2190,6 +2190,8 @@ void uvideo_vs_free_frame(struct uvideo_softc *sc) { struct uvideo_frame_buffer *fb = &sc->sc_frame_buffer; + uint8_t *mmap_buffer; + size_t mmap_buffer_size; if (fb->buf != NULL) { free(fb->buf, M_USBDEV, fb->buf_size); @@ -2197,9 +2199,12 @@ uvideo_vs_free_frame(struct uvideo_softc } if (sc->sc_mmap_buffer != NULL) { - free(sc->sc_mmap_buffer, M_USBDEV, sc->sc_mmap_buffer_size); + mmap_buffer = sc->sc_mmap_buffer; + mmap_buffer_size = sc->sc_mmap_buffer_size; sc->sc_mmap_buffer = NULL; sc->sc_mmap_buffer_size = 0; + video_mmap_revoke(mmap_buffer, mmap_buffer_size); + free(mmap_buffer, M_USBDEV, mmap_buffer_size); } while (!SIMPLEQ_EMPTY(&sc->sc_mmap_q)) @@ -3983,7 +3988,8 @@ int uvideo_reqbufs(void *v, struct v4l2_requestbuffers *rb) { struct uvideo_softc *sc = v; - int i, buf_size, buf_size_total; + uint32_t buf_size; + int i, buf_size_total; DPRINTF(1, "%s: %s: count=%d\n", DEVNAME(sc), __func__, rb->count); @@ -4005,13 +4011,14 @@ uvideo_reqbufs(void *v, struct v4l2_requ /* allocate the total mmap buffer */ buf_size = UGETDW(sc->sc_desc_probe.dwMaxVideoFrameSize); - buf_size_total = sc->sc_mmap_count * buf_size; - buf_size_total = round_page(buf_size_total); /* page align buffer */ - if (buf_size_total > MALLOC_MAX) { - printf("%s: video frame size too large!\n", DEVNAME(sc)); + if (buf_size == 0 || + buf_size > MALLOC_MAX / sc->sc_mmap_count) { + printf("%s: invalid video frame size!\n", DEVNAME(sc)); sc->sc_mmap_count = 0; return (EINVAL); } + buf_size_total = sc->sc_mmap_count * buf_size; + buf_size_total = round_page(buf_size_total); /* page align buffer */ sc->sc_mmap_buffer = malloc(buf_size_total, M_USBDEV, M_NOWAIT); if (sc->sc_mmap_buffer == NULL) { printf("%s: can't allocate mmap buffer!\n", DEVNAME(sc));