Module Name: src Committed By: riastradh Date: Tue Sep 7 10:42:48 UTC 2021
Modified Files: src/sys/dev/usb: ugen.c Log Message: ugen(4): Prevent ugenopen while ugen_set_config is in progress. (except on the control endpoint) Although we hold the kernel lock (which we should eventually change), we may sleep in usbd_set_config_no at which point ugenopen might happen and start making use of endpoint state which we'll stomp all over once usbd_set_config_no returns. Setting sc_is_open[endpt] while we wait prevents this. To generate a diff of this commit: cvs rdiff -u -r1.160 -r1.161 src/sys/dev/usb/ugen.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/usb/ugen.c diff -u src/sys/dev/usb/ugen.c:1.160 src/sys/dev/usb/ugen.c:1.161 --- src/sys/dev/usb/ugen.c:1.160 Tue Sep 7 10:42:34 2021 +++ src/sys/dev/usb/ugen.c Tue Sep 7 10:42:48 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: ugen.c,v 1.160 2021/09/07 10:42:34 riastradh Exp $ */ +/* $NetBSD: ugen.c,v 1.161 2021/09/07 10:42:48 riastradh Exp $ */ /* * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ugen.c,v 1.160 2021/09/07 10:42:34 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ugen.c,v 1.161 2021/09/07 10:42:48 riastradh Exp $"); #ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" @@ -455,6 +455,12 @@ ugen_set_config(struct ugen_softc *sc, i device_xname(sc->sc_dev), endptno)); return USBD_IN_USE; } + + /* Prevent opening while we're setting the config. */ + for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) { + KASSERT(!sc->sc_is_open[endptno]); + sc->sc_is_open[endptno] = 1; + } } /* Avoid setting the current value. */ @@ -462,23 +468,23 @@ ugen_set_config(struct ugen_softc *sc, i if (!cdesc || cdesc->bConfigurationValue != configno) { err = usbd_set_config_no(dev, configno, 1); if (err) - return err; + goto out; } ugen_clear_endpoints(sc); err = usbd_interface_count(dev, &niface); if (err) - return err; + goto out; for (ifaceno = 0; ifaceno < niface; ifaceno++) { DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno)); err = usbd_device2interface_handle(dev, ifaceno, &iface); if (err) - return err; + goto out; err = usbd_endpoint_count(iface, &nendpt); if (err) - return err; + goto out; for (endptno = 0; endptno < nendpt; endptno++) { ed = usbd_interface2endpoint_descriptor(iface,endptno); KASSERT(ed != NULL); @@ -494,7 +500,19 @@ ugen_set_config(struct ugen_softc *sc, i sce->iface = iface; } } - return USBD_NORMAL_COMPLETION; + err = USBD_NORMAL_COMPLETION; + +out: if (chkopen) { + /* + * Allow open again now that we're done trying to set + * the config. + */ + for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) { + KASSERT(sc->sc_is_open[endptno]); + sc->sc_is_open[endptno] = 0; + } + } + return err; } static int