Date: Sun, 13 Jun 2021 22:02:45 GMT From: Vladimir Kondratyev <wulf@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: 4458105f0647 - stable/13 - usbhid(4): Fix NULL pointer dereference in usbd_xfer_max_len() Message-ID: <202106132202.15DM2jIp074736@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by wulf: URL: https://cgit.FreeBSD.org/src/commit/?id=4458105f064740da227ad608ccb5c58805cfac3e commit 4458105f064740da227ad608ccb5c58805cfac3e Author: Vladimir Kondratyev <wulf@FreeBSD.org> AuthorDate: 2021-05-28 20:13:44 +0000 Commit: Vladimir Kondratyev <wulf@FreeBSD.org> CommitDate: 2021-06-13 21:57:31 +0000 usbhid(4): Fix NULL pointer dereference in usbd_xfer_max_len() Which happens when USB transfer setup is failed. PR: 254974 Reviewed by: hselasky Differential revision: https://reviews.freebsd.org/D30485 (cherry picked from commit e889a462d878675551b227a382764c3879e6c2b3) --- 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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202106132202.15DM2jIp074736>