From owner-dev-commits-src-main@freebsd.org Fri May 28 20:31:18 2021 Return-Path: Delivered-To: dev-commits-src-main@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id E4E53631C94; Fri, 28 May 2021 20:31:18 +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 "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4FsGYL69vtz4jH8; Fri, 28 May 2021 20:31:18 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (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 did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id BD20A1D937; Fri, 28 May 2021 20:31:18 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 14SKVI3U092157; Fri, 28 May 2021 20:31:18 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 14SKVIiJ092156; Fri, 28 May 2021 20:31:18 GMT (envelope-from git) Date: Fri, 28 May 2021 20:31:18 GMT Message-Id: <202105282031.14SKVIiJ092156@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Vladimir Kondratyev Subject: git: e889a462d878 - main - usbhid(4): Fix NULL pointer dereference in usbd_xfer_max_len() MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: wulf X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: e889a462d878675551b227a382764c3879e6c2b3 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-main@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for the main branch of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 28 May 2021 20:31:19 -0000 The branch main has been updated by wulf: URL: https://cgit.FreeBSD.org/src/commit/?id=e889a462d878675551b227a382764c3879e6c2b3 commit e889a462d878675551b227a382764c3879e6c2b3 Author: Vladimir Kondratyev AuthorDate: 2021-05-28 20:13:44 +0000 Commit: Vladimir Kondratyev CommitDate: 2021-05-28 20:29:42 +0000 usbhid(4): Fix NULL pointer dereference in usbd_xfer_max_len() Which happens when USB transfer setup is failed. MFC after: 1 week PR: 254974 Reviewed by: hselasky Differential revision: https://reviews.freebsd.org/D30485 --- sys/dev/usb/input/usbhid.c | 64 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/sys/dev/usb/input/usbhid.c b/sys/dev/usb/input/usbhid.c index 70b1f4ae99c2..4fb846840b8a 100644 --- a/sys/dev/usb/input/usbhid.c +++ b/sys/dev/usb/input/usbhid.c @@ -308,6 +308,22 @@ static const struct usb_config usbhid_config[USBHID_N_TRANSFER] = { }, }; +static inline usb_frlength_t +usbhid_xfer_max_len(struct usb_xfer *xfer) +{ + return (xfer == NULL ? 0 : usbd_xfer_max_len(xfer)); +} + +static inline int +usbhid_xfer_check_len(struct usbhid_softc* sc, int xfer_idx, hid_size_t len) +{ + if (sc->sc_xfer[xfer_idx] == NULL) + return (ENODEV); + if (len > usbd_xfer_max_len(sc->sc_xfer[xfer_idx])) + return (ENOBUFS); + return (0); +} + static void usbhid_intr_setup(device_t dev, hid_intr_t intr, void *context, struct hid_rdesc_info *rdesc) @@ -320,6 +336,7 @@ usbhid_intr_setup(device_t dev, hid_intr_t intr, void *context, sc->sc_intr_handler = intr; sc->sc_intr_ctx = context; bcopy(usbhid_config, sc->sc_config, sizeof(usbhid_config)); + bzero(sc->sc_xfer, sizeof(sc->sc_xfer)); /* Set buffer sizes to match HID report sizes */ sc->sc_config[USBHID_INTR_OUT_DT].bufsize = rdesc->osize; @@ -342,17 +359,15 @@ usbhid_intr_setup(device_t dev, hid_intr_t intr, void *context, sc->sc_xfer + n, sc->sc_config + n, 1, (void *)(sc->sc_xfer_ctx + n), &sc->sc_mtx); if (error) - break; + DPRINTF("xfer %d setup error=%s\n", n, + usbd_errstr(error)); } - if (error) - DPRINTF("error=%s\n", usbd_errstr(error)); - - rdesc->rdsize = usbd_xfer_max_len(sc->sc_xfer[USBHID_INTR_IN_DT]); - rdesc->grsize = usbd_xfer_max_len(sc->sc_xfer[USBHID_CTRL_DT]); + rdesc->rdsize = usbhid_xfer_max_len(sc->sc_xfer[USBHID_INTR_IN_DT]); + rdesc->grsize = usbhid_xfer_max_len(sc->sc_xfer[USBHID_CTRL_DT]); rdesc->srsize = rdesc->grsize; rdesc->wrsize = nowrite ? rdesc->srsize : - usbd_xfer_max_len(sc->sc_xfer[USBHID_INTR_OUT_DT]); + usbhid_xfer_max_len(sc->sc_xfer[USBHID_INTR_OUT_DT]); sc->sc_intr_buf = malloc(rdesc->rdsize, M_USBDEV, M_ZERO | M_WAITOK); } @@ -371,6 +386,9 @@ usbhid_intr_start(device_t dev) { struct usbhid_softc* sc = device_get_softc(dev); + if (sc->sc_xfer[USBHID_INTR_IN_DT] == NULL) + return (ENODEV); + mtx_lock(&sc->sc_mtx); sc->sc_xfer_ctx[USBHID_INTR_IN_DT] = (struct usbhid_xfer_ctx) { .req.intr.maxlen = @@ -493,8 +511,9 @@ usbhid_get_report(device_t dev, void *buf, hid_size_t maxlen, union usbhid_device_request req; int error; - if (maxlen > usbd_xfer_max_len(sc->sc_xfer[USBHID_CTRL_DT])) - return (ENOBUFS); + error = usbhid_xfer_check_len(sc, USBHID_CTRL_DT, maxlen); + if (error) + return (error); req.ctrl.bmRequestType = UT_READ_CLASS_INTERFACE; req.ctrl.bRequest = UR_GET_REPORT; @@ -516,9 +535,11 @@ usbhid_set_report(device_t dev, const void *buf, hid_size_t len, uint8_t type, { struct usbhid_softc* sc = device_get_softc(dev); union usbhid_device_request req; + int error; - if (len > usbd_xfer_max_len(sc->sc_xfer[USBHID_CTRL_DT])) - return (ENOBUFS); + error = usbhid_xfer_check_len(sc, USBHID_CTRL_DT, len); + if (error) + return (error); req.ctrl.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.ctrl.bRequest = UR_SET_REPORT; @@ -538,8 +559,9 @@ usbhid_read(device_t dev, void *buf, hid_size_t maxlen, hid_size_t *actlen) union usbhid_device_request req; int error; - if (maxlen > usbd_xfer_max_len(sc->sc_xfer[USBHID_INTR_IN_DT])) - return (ENOBUFS); + error = usbhid_xfer_check_len(sc, USBHID_INTR_IN_DT, maxlen); + if (error) + return (error); req.intr.maxlen = maxlen; error = usbhid_sync_xfer(sc, USBHID_INTR_IN_DT, &req, buf); @@ -554,9 +576,11 @@ usbhid_write(device_t dev, const void *buf, hid_size_t len) { struct usbhid_softc* sc = device_get_softc(dev); union usbhid_device_request req; + int error; - if (len > usbd_xfer_max_len(sc->sc_xfer[USBHID_INTR_OUT_DT])) - return (ENOBUFS); + error = usbhid_xfer_check_len(sc, USBHID_INTR_OUT_DT, len); + if (error) + return (error); req.intr.maxlen = len; return (usbhid_sync_xfer(sc, USBHID_INTR_OUT_DT, &req, @@ -568,6 +592,11 @@ usbhid_set_idle(device_t dev, uint16_t duration, uint8_t id) { struct usbhid_softc* sc = device_get_softc(dev); union usbhid_device_request req; + int error; + + error = usbhid_xfer_check_len(sc, USBHID_CTRL_DT, 0); + if (error) + return (error); /* Duration is measured in 4 milliseconds per unit. */ req.ctrl.bmRequestType = UT_WRITE_CLASS_INTERFACE; @@ -585,6 +614,11 @@ usbhid_set_protocol(device_t dev, uint16_t protocol) { struct usbhid_softc* sc = device_get_softc(dev); union usbhid_device_request req; + int error; + + error = usbhid_xfer_check_len(sc, USBHID_CTRL_DT, 0); + if (error) + return (error); req.ctrl.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.ctrl.bRequest = UR_SET_PROTOCOL;