From nobody Wed Jul 22 15:12:53 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4h4yRn5gKmz6mFFw for ; Wed, 22 Jul 2026 15:12:53 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4h4yRn1sZrz3kY5 for ; Wed, 22 Jul 2026 15:12:53 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1784733173; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=EN0NFLa9Qx5MG0YgPjvKWTjjeW+sdH8YGPptq5+PJFs=; b=D9GumWlhEs3/wxEGuhdQXEAkNXTd72bvNlt3CTkcYsIrPfEc34gQfgXBB9EY/8rZLaitZU zbV1MwVx3Uo9iH2xQYZCBtgvFgW8BmRw89gXn4GbjBuZMGs9yAf3Q6OmYhnmBpswc0e2rv XrXs14xNm0q/HPIAj5mHe/qUCw5KclrzuyaQ9yz9JkQ6gaiWd/u38OTaT0lXMk+xUseKJ8 4ulpAnw3oEJNqoCXadblPk9e6tZ22m3hS5y79ExwDZNr9iaK7AIHfCw7I+csuWLD6RQbGe uerXem7NDAN3tDM8TNaDFJxYb2P7N5/c8oxoLuttcnNsv+4iQRNQRTCVjanmZg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1784733173; a=rsa-sha256; cv=none; b=o6rPohDXCNQgtbaWVT3zkwF6B2HcW8IWoCUFZyA8kTUiebpZvnsfPegKNZOpj6CvpyqeY/ WVEn6MdpTCD+ViazDLPM6RJejZTbeYHYzT9qHstiiXf/eU2PdkbTnsM46roIJz3CFxBMkX jhwQXenkBkiGzuebvQfNBVy4i0NmNr4H7V3NlJd+s6VeyDakummGxnF0JGfugdR5kTb2Gg XK8rlZ2TYgLtYWKdAYN1gTR4IMDP+ek17jRtH9ucvZ81gWljrrlTC9/kjWXYjZTMy2UuBL 0+UpPpqwWUnFdTH+RjVC36/Z0Mi7fFv9sroD1PzWSMhlI9boZhewBKr0uGmp4w== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1784733173; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=EN0NFLa9Qx5MG0YgPjvKWTjjeW+sdH8YGPptq5+PJFs=; b=GP8ahyox0YGNeiphvMF5/KPJt3cJrAToT9UURkAo0kIbkBR5pjC89d/h6uo8lg/VBHvtJ6 s30FO8HQBCE6jNq06EtDsLuBlCHik8jmpn7Ua6nJGKABOjd9c+Qfz22LXyI2iIBEHkhQG1 nim1n5paXHmtXj+8GyeP9vSYDmS7crdhESW/dFxWVoFD5l6awJTCSrDYFHM93+RWNnJR/b IgFXZP7ES6RWprmBFMavSF4Gw2eKOxyUNwvjw7TjWuUCpcd7rAWFwbZ8x6UPh/NOlZj3t6 lot+6RUFQZSv+23kobWkgQNSIAt0FbhWbGZ4Dy+tEPbKRQLnRs/e9WCqGse/gQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4h4yRn0t6fz7bv for ; Wed, 22 Jul 2026 15:12:53 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 344e8 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 22 Jul 2026 15:12:53 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Baptiste Daroussin Subject: git: c141d75430c7 - main - uvideo: validate frame descriptors and fix integer overflows in size computation List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: bapt X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: c141d75430c75d21aa8260287b9e2a05905335b3 Auto-Submitted: auto-generated Date: Wed, 22 Jul 2026 15:12:53 +0000 Message-Id: <6a60ddf5.344e8.13bc6cae@gitrepo.freebsd.org> The branch main has been updated by bapt: URL: https://cgit.FreeBSD.org/src/commit/?id=c141d75430c75d21aa8260287b9e2a05905335b3 commit c141d75430c75d21aa8260287b9e2a05905335b3 Author: Baptiste Daroussin AuthorDate: 2026-07-22 12:15:21 +0000 Commit: Baptiste Daroussin CommitDate: 2026-07-22 15:10:58 +0000 uvideo: validate frame descriptors and fix integer overflows in size computation --- sys/dev/usb/video/uvideo.c | 114 ++++++++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 44 deletions(-) diff --git a/sys/dev/usb/video/uvideo.c b/sys/dev/usb/video/uvideo.c index b31b3fe294cd..a00fcc5a7395 100644 --- a/sys/dev/usb/video/uvideo.c +++ b/sys/dev/usb/video/uvideo.c @@ -233,7 +233,7 @@ struct uvideo_softc { int sc_streaming; int sc_max_ctrl_size; - int sc_max_fbuf_size; + uint32_t sc_max_fbuf_size; int sc_negotiated_flag; int sc_frame_rate; @@ -1308,6 +1308,7 @@ uvideo_vs_parse_desc(struct uvideo_softc *sc, return (error); /* Parse video stream frame descriptors */ + sc->sc_fmtgrp_idx = 0; error = uvideo_vs_parse_desc_frame(sc); if (error != USB_ERR_NORMAL_COMPLETION) return (error); @@ -1715,9 +1716,15 @@ uvideo_vs_parse_desc_frame_buffer_size(struct uvideo_softc *sc, struct usb_video_frame_desc *fd = __DECONST(struct usb_video_frame_desc *, desc); int fmtidx, frame_num; - uint32_t fbuf_size; + uint64_t fbuf_size; fmtidx = sc->sc_fmtgrp_idx; + if (fmtidx >= UVIDEO_MAX_FORMAT || + sc->sc_fmtgrp[fmtidx].format == NULL) { + device_printf(sc->sc_dev, + "frame descriptor without format!\n"); + return (USB_ERR_INVAL); + } frame_num = sc->sc_fmtgrp[fmtidx].frame_num; if (frame_num >= UVIDEO_MAX_FRAME) { device_printf(sc->sc_dev, @@ -1744,7 +1751,7 @@ uvideo_vs_parse_desc_frame_buffer_size(struct uvideo_softc *sc, fbuf_size = UGETDW(fd->u.uc.dwMaxVideoFrameBufferSize); if (fbuf_size > sc->sc_max_fbuf_size) - sc->sc_max_fbuf_size = fbuf_size; + sc->sc_max_fbuf_size = (uint32_t)fbuf_size; if (++sc->sc_fmtgrp[fmtidx].frame_num == sc->sc_fmtgrp[fmtidx].format->bNumFrameDescriptors) @@ -1761,9 +1768,16 @@ uvideo_vs_parse_desc_frame_max_rate(struct uvideo_softc *sc, __DECONST(struct usb_video_frame_desc *, desc); uint8_t *p; int i, fmtidx, frame_num, length, nivals; - uint32_t fbuf_size, frame_ival, next_frame_ival; + uint64_t fbuf_size; + uint32_t frame_ival, next_frame_ival; fmtidx = sc->sc_fmtgrp_idx; + if (fmtidx >= UVIDEO_MAX_FORMAT || + sc->sc_fmtgrp[fmtidx].format == NULL) { + device_printf(sc->sc_dev, + "frame descriptor without format!\n"); + return (USB_ERR_INVAL); + } frame_num = sc->sc_fmtgrp[fmtidx].frame_num; if (frame_num >= UVIDEO_MAX_FRAME) { device_printf(sc->sc_dev, @@ -1803,7 +1817,7 @@ uvideo_vs_parse_desc_frame_max_rate(struct uvideo_softc *sc, fbuf_size /= 8 * 10000000; if (fbuf_size > sc->sc_max_fbuf_size) - sc->sc_max_fbuf_size = fbuf_size; + sc->sc_max_fbuf_size = (uint32_t)fbuf_size; if (++sc->sc_fmtgrp[fmtidx].frame_num == sc->sc_fmtgrp[fmtidx].format->bNumFrameDescriptors) @@ -2240,7 +2254,7 @@ uvideo_vs_alloc_frame(struct uvideo_softc *sc) fb->buf_size = UGETDW(sc->sc_desc_probe.dwMaxVideoFrameSize); - if (sc->sc_max_fbuf_size < fb->buf_size && sc->sc_mmap_flag == 0) { + if (sc->sc_max_fbuf_size < fb->buf_size) { device_printf(sc->sc_dev, "software video buffer too small!\n"); return (USB_ERR_NOMEM); @@ -2948,47 +2962,58 @@ uvideo_cdev_read(struct cdev *dev, struct uio *uio, int ioflag) return (EIO); /* Start streaming in read mode if not already running */ - if (sc->sc_vidmode == VIDMODE_NONE) { - if (devfs_get_cdevpriv((void **)&priv) != 0 || priv == NULL) - return (EINVAL); - sc->sc_mmap_flag = 0; - sc->sc_vidmode = VIDMODE_READ; + mtx_lock(&sc->sc_mtx); + if (sc->sc_vidmode != VIDMODE_NONE) { + mtx_unlock(&sc->sc_mtx); + if (sc->sc_vidmode != VIDMODE_READ) + return (EBUSY); + goto read_wait; + } + if (devfs_get_cdevpriv((void **)&priv) != 0 || priv == NULL) { + mtx_unlock(&sc->sc_mtx); + return (EINVAL); + } + sc->sc_mmap_flag = 0; + sc->sc_vidmode = VIDMODE_READ; + mtx_unlock(&sc->sc_mtx); - error = uvideo_vs_init(sc); - if (error != USB_ERR_NORMAL_COMPLETION) { - sc->sc_vidmode = VIDMODE_NONE; - return (EIO); - } + error = uvideo_vs_init(sc); + if (error != USB_ERR_NORMAL_COMPLETION) { + mtx_lock(&sc->sc_mtx); + sc->sc_vidmode = VIDMODE_NONE; + mtx_unlock(&sc->sc_mtx); + return (EIO); + } - /* Allocate a separate read buffer for frame delivery */ - sc->sc_fbufferlen = sc->sc_max_fbuf_size; - if (sc->sc_fbufferlen == 0) - sc->sc_fbufferlen = - UGETDW(sc->sc_desc_probe.dwMaxVideoFrameSize); + /* Allocate a separate read buffer for frame delivery */ + sc->sc_fbufferlen = sc->sc_max_fbuf_size; + if (sc->sc_fbufferlen == 0) + sc->sc_fbufferlen = + UGETDW(sc->sc_desc_probe.dwMaxVideoFrameSize); + if (sc->sc_fbuffer == NULL) { + sc->sc_fbuffer = malloc(sc->sc_fbufferlen, M_USBDEV, + M_WAITOK | M_ZERO); if (sc->sc_fbuffer == NULL) { - sc->sc_fbuffer = malloc(sc->sc_fbufferlen, M_USBDEV, - M_WAITOK | M_ZERO); - if (sc->sc_fbuffer == NULL) { - sc->sc_vidmode = VIDMODE_NONE; - return (ENOMEM); - } + mtx_lock(&sc->sc_mtx); + sc->sc_vidmode = VIDMODE_NONE; + mtx_unlock(&sc->sc_mtx); + return (ENOMEM); } + } - mtx_lock(&sc->sc_mtx); - sc->sc_streaming = 1; - priv->streaming = 1; - if (sc->sc_vs_cur->bulk_endpoint) - usbd_transfer_start(sc->sc_xfer[0]); - else { - int i; - for (i = 0; i < UVIDEO_IXFERS; i++) - usbd_transfer_start(sc->sc_xfer[i]); - } - mtx_unlock(&sc->sc_mtx); + mtx_lock(&sc->sc_mtx); + sc->sc_streaming = 1; + priv->streaming = 1; + if (sc->sc_vs_cur->bulk_endpoint) + usbd_transfer_start(sc->sc_xfer[0]); + else { + int i; + for (i = 0; i < UVIDEO_IXFERS; i++) + usbd_transfer_start(sc->sc_xfer[i]); } + mtx_unlock(&sc->sc_mtx); - if (sc->sc_vidmode != VIDMODE_READ) - return (EBUSY); +read_wait: /* Wait for a frame */ mtx_lock(&sc->sc_mtx); @@ -3181,7 +3206,9 @@ uvideo_cdev_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_object_reference(sc->sc_mmap_object); *object = sc->sc_mmap_object; + mtx_lock(&sc->sc_mtx); sc->sc_mmap_flag = 1; + mtx_unlock(&sc->sc_mtx); return (0); } @@ -3430,7 +3457,7 @@ uvideo_s_fmt(struct uvideo_softc *sc, struct v4l2_format *fmt) * and commit controls with the device would disrupt the active USB * transfers. V4L2 mandates EBUSY in this case. */ mtx_lock(&sc->sc_mtx); - if (sc->sc_streaming) { + if (sc->sc_streaming || sc->sc_mmap_count > 0) { mtx_unlock(&sc->sc_mtx); return (EBUSY); } @@ -3520,7 +3547,7 @@ uvideo_s_parm(struct uvideo_softc *sc, struct v4l2_streamparm *parm) /* Reject parameter changes while streaming for the same reason as * S_FMT: they re-negotiate with the device. */ mtx_lock(&sc->sc_mtx); - if (sc->sc_streaming) { + if (sc->sc_streaming || sc->sc_mmap_count > 0) { mtx_unlock(&sc->sc_mtx); return (EBUSY); } @@ -3632,8 +3659,7 @@ uvideo_reqbufs(struct uvideo_softc *sc, struct v4l2_requestbuffers *rb) sc->sc_mmap_count = rb->count; buf_size = UGETDW(sc->sc_desc_probe.dwMaxVideoFrameSize); - if (buf_size == 0 || sc->sc_max_fbuf_size <= 0 || - buf_size > (u_int)sc->sc_max_fbuf_size) + if (buf_size == 0 || buf_size > sc->sc_max_fbuf_size) return (EINVAL); if (SIZE_MAX / sc->sc_mmap_count < buf_size) return (EINVAL);