usbd_set_config_index() is a complex function parsing unstrusted USB
descriptors. If a device presents itself with malformed descriptors
we should stop probing as soon as possible.
Our USB stack has a way to attach unconfigured USB devices to drivers,
meaning that such drivers have to call usbd_set_config_index() in their
*_attach() function. This is bad because *_attach() functions do not
return errors and, in the best case, the kernel ends up with an attached
but unusable driver.
In the worst case this ends up in a panic, generally when the device
is detached. I'll send one diff per panic as I found them with the
fuzzer I got. In the meantime I'd like to commit the diff below which
changes all the drivers using the first configuration, with index 0, to
let the stack call usbd_set_config_index() for them.
Ok?
Index: uhub.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uhub.c,v
retrieving revision 1.88
diff -u -p -r1.88 uhub.c
--- uhub.c 29 Nov 2015 16:30:48 -0000 1.88
+++ uhub.c 1 Sep 2016 12:47:31 -0000
@@ -102,11 +102,14 @@ uhub_match(struct device *parent, void *
struct usb_attach_arg *uaa = aux;
usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device);
+ if (uaa->iface == NULL)
+ return (UMATCH_NONE);
+
/*
* The subclass for hubs seems to be 0 for some and 1 for others,
* so we just ignore the subclass.
*/
- if (uaa->iface == NULL && dd->bDeviceClass == UDCLASS_HUB)
+ if (dd->bDeviceClass == UDCLASS_HUB)
return (UMATCH_DEVCLASS_DEVSUBCLASS);
return (UMATCH_NONE);
}
@@ -134,13 +137,6 @@ uhub_attach(struct device *parent, struc
sc->sc_hub = dev;
- err = usbd_set_config_index(dev, 0, 1);
- if (err) {
- DPRINTF("%s: configuration failed, error=%s\n",
- sc->sc_dev.dv_xname, usbd_errstr(err));
- return;
- }
-
if (dev->depth > USB_HUB_MAX_DEPTH) {
printf("%s: hub depth (%d) exceeded, hub ignored\n",
sc->sc_dev.dv_xname, USB_HUB_MAX_DEPTH);
@@ -324,10 +320,10 @@ uhub_attach(struct device *parent, struc
for (port = 1; port <= nports; port++) {
/* Turn the power on. */
err = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
- if (err)
- printf("%s: port %d power on failed, %s\n",
- sc->sc_dev.dv_xname, port,
- usbd_errstr(err));
+ if (err) {
+ DPRINTF("%s: port %d power on failed, %s\n",
+ sc->sc_dev.dv_xname, port, usbd_errstr(err));
+ }
/* Make sure we check the port status at least once. */
sc->sc_status |= (1 << port);
}
Index: moscom.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/moscom.c,v
retrieving revision 1.23
diff -u -p -r1.23 moscom.c
--- moscom.c 7 Jan 2016 12:53:37 -0000 1.23
+++ moscom.c 1 Sep 2016 11:49:33 -0000
@@ -30,7 +30,6 @@
#include <dev/usb/ucomvar.h>
#define MOSCOMBUFSZ 256
-#define MOSCOM_CONFIG_INDEX 0
#define MOSCOM_IFACE_NO 0
#define MOSCOM_READ 0x0d
@@ -178,7 +177,7 @@ moscom_match(struct device *parent, void
{
struct usb_attach_arg *uaa = aux;
- if (uaa->iface != NULL)
+ if (uaa->iface == NULL)
return UMATCH_NONE;
return (usb_lookup(moscom_devs, uaa->vendor, uaa->product) != NULL) ?
@@ -198,13 +197,6 @@ moscom_attach(struct device *parent, str
bzero(&uca, sizeof(uca));
sc->sc_udev = uaa->device;
-
- if (usbd_set_config_index(sc->sc_udev, MOSCOM_CONFIG_INDEX, 1) != 0) {
- printf("%s: could not set configuration no\n",
- sc->sc_dev.dv_xname);
- usbd_deactivate(sc->sc_udev);
- return;
- }
/* get the first interface handle */
error = usbd_device2interface_handle(sc->sc_udev, MOSCOM_IFACE_NO,
Index: uark.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uark.c,v
retrieving revision 1.23
diff -u -p -r1.23 uark.c
--- uark.c 7 Jan 2016 12:53:37 -0000 1.23
+++ uark.c 1 Sep 2016 11:50:05 -0000
@@ -38,7 +38,6 @@ int uarkebug = 0;
#define DPRINTF(x) DPRINTFN(0, x)
#define UARKBUFSZ 256
-#define UARK_CONFIG_INDEX 0
#define UARK_IFACE_NO 0
#define UARK_SET_DATA_BITS(x) (x - 5)
@@ -105,7 +104,7 @@ uark_match(struct device *parent, void *
{
struct usb_attach_arg *uaa = aux;
- if (uaa->iface != NULL)
+ if (uaa->iface == NULL)
return UMATCH_NONE;
return (usb_lookup(uark_devs, uaa->vendor, uaa->product) != NULL) ?
@@ -125,13 +124,6 @@ uark_attach(struct device *parent, struc
bzero(&uca, sizeof(uca));
sc->sc_udev = uaa->device;
-
- if (usbd_set_config_index(sc->sc_udev, UARK_CONFIG_INDEX, 1) != 0) {
- printf("%s: could not set configuration no\n",
- sc->sc_dev.dv_xname);
- usbd_deactivate(sc->sc_udev);
- return;
- }
/* get the first interface handle */
error = usbd_device2interface_handle(sc->sc_udev, UARK_IFACE_NO,
Index: uchcom.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uchcom.c,v
retrieving revision 1.24
diff -u -p -r1.24 uchcom.c
--- uchcom.c 14 Apr 2015 07:57:33 -0000 1.24
+++ uchcom.c 1 Sep 2016 11:50:58 -0000
@@ -56,7 +56,6 @@ int uchcomdebug = 0;
#define DPRINTF(x) DPRINTFN(0, x)
#define UCHCOM_IFACE_INDEX 0
-#define UCHCOM_CONFIG_INDEX 0
#define UCHCOM_REV_CH340 0x0250
#define UCHCOM_INPUT_BUF_SIZE 8
@@ -165,7 +164,6 @@ int uchcom_open(void *, int);
void uchcom_close(void *, int);
void uchcom_intr(struct usbd_xfer *, void *, usbd_status);
-int uchcom_set_config(struct uchcom_softc *);
int uchcom_find_ifaces(struct uchcom_softc *,
struct usbd_interface **);
int uchcom_find_endpoints(struct uchcom_softc *,
@@ -237,7 +235,7 @@ uchcom_match(struct device *parent, void
{
struct usb_attach_arg *uaa = aux;
- if (uaa->iface != NULL)
+ if (uaa->iface == NULL)
return UMATCH_NONE;
return (usb_lookup(uchcom_devs, uaa->vendor, uaa->product) != NULL ?
@@ -259,9 +257,6 @@ uchcom_attach(struct device *parent, str
DPRINTF(("\n\nuchcom attach: sc=%p\n", sc));
- if (uchcom_set_config(sc))
- goto failed;
-
switch (uaa->release) {
case UCHCOM_REV_CH340:
printf("%s: CH340\n", sc->sc_dev.dv_xname);
@@ -318,21 +313,6 @@ uchcom_detach(struct device *self, int f
}
return rv;
-}
-
-int
-uchcom_set_config(struct uchcom_softc *sc)
-{
- usbd_status err;
-
- err = usbd_set_config_index(sc->sc_udev, UCHCOM_CONFIG_INDEX, 1);
- if (err) {
- printf("%s: failed to set configuration: %s\n",
- sc->sc_dev.dv_xname, usbd_errstr(err));
- return -1;
- }
-
- return 0;
}
int
Index: udcf.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/udcf.c,v
retrieving revision 1.60
diff -u -p -r1.60 udcf.c
--- udcf.c 7 Jun 2015 20:11:52 -0000 1.60
+++ udcf.c 1 Sep 2016 11:51:35 -0000
@@ -147,7 +147,7 @@ udcf_match(struct device *parent, void *
{
struct usb_attach_arg *uaa = aux;
- if (uaa->iface != NULL)
+ if (uaa->iface == NULL)
return UMATCH_NONE;
return (usb_lookup(udcf_devs, uaa->vendor, uaa->product) != NULL ?
@@ -205,12 +205,6 @@ udcf_attach(struct device *parent, struc
sensordev_install(&sc->sc_sensordev);
sc->sc_udev = dev;
- if ((err = usbd_set_config_index(dev, 0, 1))) {
- DPRINTF(("%s: failed to set configuration, err=%s\n",
- sc->sc_dev.dv_xname, usbd_errstr(err)));
- goto fishy;
- }
-
if ((err = usbd_device2interface_handle(dev, 0, &iface))) {
DPRINTF(("%s: failed to get interface, err=%s\n",
sc->sc_dev.dv_xname, usbd_errstr(err)));
Index: umbg.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/umbg.c,v
retrieving revision 1.23
diff -u -p -r1.23 umbg.c
--- umbg.c 12 Jul 2014 20:26:33 -0000 1.23
+++ umbg.c 1 Sep 2016 11:51:53 -0000
@@ -154,7 +154,7 @@ umbg_match(struct device *parent, void *
{
struct usb_attach_arg *uaa = aux;
- if (uaa->iface != NULL)
+ if (uaa->iface == NULL)
return UMATCH_NONE;
return uaa->vendor == USB_VENDOR_MEINBERG &&
@@ -195,12 +195,6 @@ umbg_attach(struct device *parent, struc
usb_init_task(&sc->sc_task, umbg_task, sc, USB_TASK_TYPE_GENERIC);
timeout_set(&sc->sc_to, umbg_intr, sc);
timeout_set(&sc->sc_it_to, umbg_it_intr, sc);
-
- if ((err = usbd_set_config_index(dev, 0, 1))) {
- printf("%s: failed to set configuration, err=%s\n",
- sc->sc_dev.dv_xname, usbd_errstr(err));
- goto fishy;
- }
if ((err = usbd_device2interface_handle(dev, 0, &iface))) {
printf("%s: failed to get interface, err=%s\n",
Index: umct.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/umct.c,v
retrieving revision 1.44
diff -u -p -r1.44 umct.c
--- umct.c 26 Apr 2015 06:38:04 -0000 1.44
+++ umct.c 1 Sep 2016 11:52:19 -0000
@@ -66,7 +66,6 @@ int umctdebug = 0;
#endif
#define DPRINTF(x) DPRINTFN(0, x)
-#define UMCT_CONFIG_INDEX 0
#define UMCT_IFACE_INDEX 0
struct umct_softc {
@@ -159,7 +158,7 @@ umct_match(struct device *parent, void *
{
struct usb_attach_arg *uaa = aux;
- if (uaa->iface != NULL)
+ if (uaa->iface == NULL)
return (UMATCH_NONE);
return (usb_lookup(umct_devs, uaa->vendor, uaa->product) != NULL ?
@@ -190,15 +189,6 @@ umct_attach(struct device *parent, struc
uca.bulkin = uca.bulkout = -1;
sc->sc_intr_number = -1;
sc->sc_intr_pipe = NULL;
-
- /* Move the device into the configured state. */
- err = usbd_set_config_index(dev, UMCT_CONFIG_INDEX, 1);
- if (err) {
- printf("\n%s: failed to set configuration, err=%s\n",
- devname, usbd_errstr(err));
- usbd_deactivate(sc->sc_udev);
- return;
- }
/* get the config descriptor */
cdesc = usbd_get_config_descriptor(sc->sc_udev);
Index: uonerng.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uonerng.c,v
retrieving revision 1.1
diff -u -p -r1.1 uonerng.c
--- uonerng.c 8 Jan 2016 09:36:59 -0000 1.1
+++ uonerng.c 1 Sep 2016 11:52:53 -0000
@@ -97,7 +97,6 @@
#define ONERNG_RF "cmd7\n"
-#define ONERNG_CONFIG_INDEX 0
#define ONERNG_IFACE_CTRL_INDEX 0
#define ONERNG_IFACE_DATA_INDEX 1
@@ -150,7 +149,7 @@ uonerng_match(struct device *parent, voi
{
struct usb_attach_arg *uaa = aux;
- if (uaa->iface != NULL)
+ if (uaa->iface == NULL)
return UMATCH_NONE;
if (uaa->vendor != USB_VENDOR_OPENMOKO2 ||
@@ -178,13 +177,6 @@ uonerng_attach(struct device *parent, st
sc->sc_first_run = 1;
usb_init_task(&sc->sc_task, uonerng_task, sc, USB_TASK_TYPE_GENERIC);
-
- err = usbd_set_config_index(sc->sc_udev, ONERNG_CONFIG_INDEX, 1);
- if (err) {
- printf("%s: failed to set configuration, err=%s\n",
- DEVNAME(sc), usbd_errstr(err));
- goto fail;
- }
/* locate the control interface number and the data interface */
err = usbd_device2interface_handle(sc->sc_udev,
Index: uplcom.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uplcom.c,v
retrieving revision 1.67
diff -u -p -r1.67 uplcom.c
--- uplcom.c 24 May 2016 05:35:01 -0000 1.67
+++ uplcom.c 1 Sep 2016 11:53:11 -0000
@@ -66,7 +66,6 @@ int uplcomdebug = 0;
#endif
#define DPRINTF(x) DPRINTFN(0, x)
-#define UPLCOM_CONFIG_INDEX 0
#define UPLCOM_IFACE_INDEX 0
#define UPLCOM_SECOND_IFACE_INDEX 1
@@ -195,7 +194,7 @@ uplcom_match(struct device *parent, void
{
struct usb_attach_arg *uaa = aux;
- if (uaa->iface != NULL)
+ if (uaa->iface == NULL)
return (UMATCH_NONE);
return (uplcom_lookup(uaa->vendor, uaa->product) != NULL ?
@@ -225,15 +224,6 @@ uplcom_attach(struct device *parent, str
uca.bulkin = uca.bulkout = -1;
sc->sc_intr_number = -1;
sc->sc_intr_pipe = NULL;
-
- /* Move the device into the configured state. */
- err = usbd_set_config_index(dev, UPLCOM_CONFIG_INDEX, 1);
- if (err) {
- printf("%s: failed to set configuration, err=%s\n",
- devname, usbd_errstr(err));
- usbd_deactivate(sc->sc_udev);
- return;
- }
/* get the config descriptor */
cdesc = usbd_get_config_descriptor(sc->sc_udev);
Index: uscom.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uscom.c,v
retrieving revision 1.4
diff -u -p -r1.4 uscom.c
--- uscom.c 7 Jan 2016 12:53:37 -0000 1.4
+++ uscom.c 1 Sep 2016 11:53:37 -0000
@@ -31,7 +31,6 @@
#include <dev/usb/ucomvar.h>
#define USCOMBUFSZ 256
-#define USCOM_CONFIG_INDEX 0
#define USCOM_IFACE_NO 0
struct uscom_softc {
@@ -73,7 +72,7 @@ uscom_match(struct device *parent, void
{
struct usb_attach_arg *uaa = aux;
- if (uaa->iface != NULL)
+ if (uaa->iface == NULL)
return UMATCH_NONE;
return (usb_lookup(uscom_devs, uaa->vendor, uaa->product) != NULL) ?
@@ -93,13 +92,6 @@ uscom_attach(struct device *parent, stru
bzero(&uca, sizeof(uca));
sc->sc_udev = uaa->device;
-
- if (usbd_set_config_index(sc->sc_udev, USCOM_CONFIG_INDEX, 1) != 0) {
- printf("%s: could not set configuration no\n",
- sc->sc_dev.dv_xname);
- usbd_deactivate(sc->sc_udev);
- return;
- }
/* get the first interface handle */
error = usbd_device2interface_handle(sc->sc_udev, USCOM_IFACE_NO,
Index: uslcom.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uslcom.c,v
retrieving revision 1.38
diff -u -p -r1.38 uslcom.c
--- uslcom.c 31 Mar 2016 12:41:46 -0000 1.38
+++ uslcom.c 1 Sep 2016 11:54:01 -0000
@@ -38,7 +38,6 @@ int uslcomdebug = 0;
#define DPRINTF(x) DPRINTFN(0, x)
#define USLCOMBUFSZ 256
-#define USLCOM_CONFIG_INDEX 0
#define USLCOM_IFACE_NO 0
#define USLCOM_SET_DATA_BITS(x) (x << 8)
@@ -277,7 +276,7 @@ uslcom_match(struct device *parent, void
{
struct usb_attach_arg *uaa = aux;
- if (uaa->iface != NULL)
+ if (uaa->iface == NULL)
return UMATCH_NONE;
return (usb_lookup(uslcom_devs, uaa->vendor, uaa->product) != NULL) ?
@@ -297,13 +296,6 @@ uslcom_attach(struct device *parent, str
bzero(&uca, sizeof(uca));
sc->sc_udev = uaa->device;
-
- if (usbd_set_config_index(sc->sc_udev, USLCOM_CONFIG_INDEX, 1) != 0) {
- printf("%s: could not set configuration no\n",
- sc->sc_dev.dv_xname);
- usbd_deactivate(sc->sc_udev);
- return;
- }
/* get the first interface handle */
error = usbd_device2interface_handle(sc->sc_udev, USLCOM_IFACE_NO,
Index: uts.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uts.c,v
retrieving revision 1.38
diff -u -p -r1.38 uts.c
--- uts.c 5 Jun 2016 20:15:54 -0000 1.38
+++ uts.c 1 Sep 2016 11:54:37 -0000
@@ -44,8 +44,6 @@
#define DPRINTF(x)
#endif
-#define UTS_CONFIG_INDEX 0
-
struct tsscale {
int minx, maxx;
int miny, maxy;
@@ -162,14 +160,6 @@ uts_attach(struct device *parent, struct
/* Copy the default scalue values to each softc */
bcopy(&def_scale, &sc->sc_tsscale, sizeof(sc->sc_tsscale));
-
- /* Move the device into the configured state. */
- if (usbd_set_config_index(uaa->device, UTS_CONFIG_INDEX, 1) != 0) {
- printf("%s: could not set configuartion no\n",
- sc->sc_dev.dv_xname);
- usbd_deactivate(sc->sc_udev);
- return;
- }
/* get the config descriptor */
cdesc = usbd_get_config_descriptor(sc->sc_udev);
Index: uvisor.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uvisor.c,v
retrieving revision 1.50
diff -u -p -r1.50 uvisor.c
--- uvisor.c 14 Mar 2015 03:38:50 -0000 1.50
+++ uvisor.c 1 Sep 2016 11:54:57 -0000
@@ -59,7 +59,6 @@ int uvisordebug = 0;
#define DPRINTFN(n,x)
#endif
-#define UVISOR_CONFIG_INDEX 0
#define UVISOR_IFACE_INDEX 0
/* From the Linux driver */
@@ -209,7 +208,7 @@ uvisor_match(struct device *parent, void
{
struct usb_attach_arg *uaa = aux;
- if (uaa->iface != NULL)
+ if (uaa->iface == NULL)
return (UMATCH_NONE);
DPRINTFN(20,("uvisor: vendor=0x%x, product=0x%x\n",
@@ -235,14 +234,6 @@ uvisor_attach(struct device *parent, str
struct ucom_attach_args uca;
DPRINTFN(10,("\nuvisor_attach: sc=%p\n", sc));
-
- /* Move the device into the configured state. */
- err = usbd_set_config_index(dev, UVISOR_CONFIG_INDEX, 1);
- if (err) {
- printf(": failed to set configuration, err=%s\n",
- usbd_errstr(err));
- goto bad;
- }
err = usbd_device2interface_handle(dev, UVISOR_IFACE_INDEX, &iface);
if (err) {
Index: uvscom.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uvscom.c,v
retrieving revision 1.33
diff -u -p -r1.33 uvscom.c
--- uvscom.c 14 Mar 2015 03:38:50 -0000 1.33
+++ uvscom.c 1 Sep 2016 11:55:19 -0000
@@ -65,7 +65,6 @@ static int uvscomdebug = 1;
#endif
#define DPRINTF(x) DPRINTFN(0, x)
-#define UVSCOM_CONFIG_INDEX 0
#define UVSCOM_IFACE_INDEX 0
#define UVSCOM_INTR_INTERVAL 100 /* mS */
@@ -219,7 +218,7 @@ uvscom_match(struct device *parent, void
{
struct usb_attach_arg *uaa = aux;
- if (uaa->iface != NULL)
+ if (uaa->iface == NULL)
return (UMATCH_NONE);
return (usb_lookup(uvscom_devs, uaa->vendor, uaa->product) != NULL ?
@@ -248,15 +247,6 @@ uvscom_attach(struct device *parent, str
uca.bulkin = uca.bulkout = -1;
sc->sc_intr_number = -1;
sc->sc_intr_pipe = NULL;
-
- /* Move the device into the configured state. */
- err = usbd_set_config_index(dev, UVSCOM_CONFIG_INDEX, 1);
- if (err) {
- printf("%s: failed to set configuration, err=%s\n",
- devname, usbd_errstr(err));
- usbd_deactivate(sc->sc_udev);
- return;
- }
/* get the config descriptor */
cdesc = usbd_get_config_descriptor(sc->sc_udev);