Date: Wed, 22 Jul 2026 15:12:48 +0000 From: Baptiste Daroussin <bapt@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: cb26bda8ca36 - main - uvideo: bounds-check frame interval reads against bLength Message-ID: <6a60ddf0.3377f.5adea594@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by bapt: URL: https://cgit.FreeBSD.org/src/commit/?id=cb26bda8ca36e0e421f75d82e1aa46df8f2ff814 commit cb26bda8ca36e0e421f75d82e1aa46df8f2ff814 Author: Baptiste Daroussin <bapt@FreeBSD.org> AuthorDate: 2026-07-22 07:42:29 +0000 Commit: Baptiste Daroussin <bapt@FreeBSD.org> CommitDate: 2026-07-22 15:10:57 +0000 uvideo: bounds-check frame interval reads against bLength Frame interval data is read from device-supplied frame descriptors whose bLength may be shorter than the number of intervals declared by bFrameIntervalType. The continuous branch of uvideo_enum_fivals() read three intervals unconditionally, and the discrete branch checked the pointer but not the four bytes that UGETDW() reads, so a short or malformed descriptor could read past bLength and leak adjacent kernel memory to userspace. uvideo_vs_parse_desc_frame_max_rate() had the same class of off-by-up-to-three-bytes read. Compute the available bytes from bLength and validate before each read. Reported by: emaste --- sys/dev/usb/video/uvideo.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sys/dev/usb/video/uvideo.c b/sys/dev/usb/video/uvideo.c index 708660adeafb..ac54eba19695 100644 --- a/sys/dev/usb/video/uvideo.c +++ b/sys/dev/usb/video/uvideo.c @@ -1791,7 +1791,7 @@ uvideo_vs_parse_desc_frame_max_rate(struct uvideo_softc *sc, nivals = UVIDEO_FRAME_NUM_INTERVALS(fd); for (i = 0; i < nivals; i++) { - if (length <= 0) + if (length < (int)sizeof(uDWord)) break; next_frame_ival = UGETDW(p); if (next_frame_ival > frame_ival) @@ -3294,7 +3294,7 @@ uvideo_enum_fsizes(struct uvideo_softc *sc, struct v4l2_frmsizeenum *fsizes) static int uvideo_enum_fivals(struct uvideo_softc *sc, struct v4l2_frmivalenum *fivals) { - int idx; + int idx, ival_bytes; struct uvideo_format_group *fmtgrp = NULL; struct usb_video_frame_desc *frame = NULL; uint8_t *p; @@ -3327,6 +3327,9 @@ uvideo_enum_fivals(struct uvideo_softc *sc, struct v4l2_frmivalenum *fivals) return (EINVAL); p = (uint8_t *)frame + UVIDEO_FRAME_MIN_LEN(frame); + ival_bytes = (int)frame->bLength - (int)UVIDEO_FRAME_MIN_LEN(frame); + if (ival_bytes < 0) + return (EINVAL); bzero(fivals, sizeof(*fivals)); fivals->index = fi_index; @@ -3337,6 +3340,8 @@ uvideo_enum_fivals(struct uvideo_softc *sc, struct v4l2_frmivalenum *fivals) if (UVIDEO_FRAME_NUM_INTERVALS(frame) == 0) { if (fi_index != 0) return (EINVAL); + if (ival_bytes < (int)(3 * sizeof(uDWord))) + return (EINVAL); fivals->type = V4L2_FRMIVAL_TYPE_STEPWISE; fivals->stepwise.min.numerator = UGETDW(p); fivals->stepwise.min.denominator = 10000000; @@ -3349,12 +3354,9 @@ uvideo_enum_fivals(struct uvideo_softc *sc, struct v4l2_frmivalenum *fivals) } else { if (fi_index >= (uint32_t)UVIDEO_FRAME_NUM_INTERVALS(frame)) return (EINVAL); - p += sizeof(uDWord) * fi_index; - if (p > frame->bLength + (uint8_t *)frame) { - device_printf(sc->sc_dev, - "frame desc too short?\n"); + if (ival_bytes < (int)((fi_index + 1) * sizeof(uDWord))) return (EINVAL); - } + p += sizeof(uDWord) * fi_index; fivals->type = V4L2_FRMIVAL_TYPE_DISCRETE; fivals->discrete.numerator = UGETDW(p); fivals->discrete.denominator = 10000000;home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a60ddf0.3377f.5adea594>
