From beb501f39435a2d47471ff8d48021b31c61efc55 Mon Sep 17 00:00:00 2001 From: jmorse Date: Fri, 12 Dec 2008 05:35:11 +0000 Subject: [PATCH] PR#39651 Fix two problems in umass: * usb xfers being freed before being removed from pipe, leading to null deref * config_activate requests not supported, which leads to config_deactivate requests not being passed through. Spotted by jmcneill@ Added mechanism to usbdi allowing the default pipe to be aborted --- sys/dev/usb/umass.c | 32 ++++++++++++++++++++------------ sys/dev/usb/usbdi.c | 13 +++++++++++-- sys/dev/usb/usbdi.h | 3 ++- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/sys/dev/usb/umass.c b/sys/dev/usb/umass.c index 05ffc5a966a9..023775f0ca4a 100644 --- a/sys/dev/usb/umass.c +++ b/sys/dev/usb/umass.c @@ -1,4 +1,4 @@ -/* $NetBSD: umass.c,v 1.129 2008/09/06 21:49:00 rmind Exp $ */ +/* $NetBSD: umass.c,v 1.130 2008/12/12 05:35:11 jmorse Exp $ */ /* * Copyright (c) 2003 The NetBSD Foundation, Inc. @@ -124,7 +124,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: umass.c,v 1.129 2008/09/06 21:49:00 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: umass.c,v 1.130 2008/12/12 05:35:11 jmorse Exp $"); #include "atapibus.h" #include "scsibus.h" @@ -692,7 +692,11 @@ umass_activate(device_t dev, enum devact act) switch (act) { case DVACT_ACTIVATE: - rv = EOPNOTSUPP; + if (scbus == NULL || scbus->sc_child == NULL) + break; + rv = config_activate(scbus->sc_child); + DPRINTF(UDMASS_USB, ("%s: umass activate: child " + "returned %d\n", USBDEVNAME(sc->sc_dev), rv)); break; case DVACT_DEACTIVATE: @@ -700,7 +704,7 @@ umass_activate(device_t dev, enum devact act) if (scbus == NULL || scbus->sc_child == NULL) break; rv = config_deactivate(scbus->sc_child); - DPRINTF(UDMASS_USB, ("%s: umass_activate: child " + DPRINTF(UDMASS_USB, ("%s: umass_deactivate: child " "returned %d\n", USBDEVNAME(sc->sc_dev), rv)); break; } @@ -714,20 +718,24 @@ umass_disco(struct umass_softc *sc) DPRINTF(UDMASS_GEN, ("umass_disco\n")); + /* Remove all the pipes. */ + for (i = 0 ; i < UMASS_NEP ; i++) { + if (sc->sc_pipe[i] != NULL) { + usbd_abort_pipe(sc->sc_pipe[i]); + usbd_close_pipe(sc->sc_pipe[i]); + sc->sc_pipe[i] = NULL; + } + } + + /* Some xfers may be queued in the default pipe */ + usbd_abort_default_pipe(sc->sc_udev); + /* Free the xfers. */ for (i = 0; i < XFER_NR; i++) if (sc->transfer_xfer[i] != NULL) { usbd_free_xfer(sc->transfer_xfer[i]); sc->transfer_xfer[i] = NULL; } - - /* Remove all the pipes. */ - for (i = 0 ; i < UMASS_NEP ; i++) { - if (sc->sc_pipe[i] != NULL) { - usbd_close_pipe(sc->sc_pipe[i]); - sc->sc_pipe[i] = NULL; - } - } } /* diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c index a0616dede708..d0f325cf45b3 100644 --- a/sys/dev/usb/usbdi.c +++ b/sys/dev/usb/usbdi.c @@ -1,4 +1,4 @@ -/* $NetBSD: usbdi.c,v 1.124 2008/10/11 05:07:20 jmcneill Exp $ */ +/* $NetBSD: usbdi.c,v 1.125 2008/12/12 05:35:11 jmorse Exp $ */ /* $FreeBSD: src/sys/dev/usb/usbdi.c,v 1.28 1999/11/17 22:33:49 n_hibma Exp $ */ /* @@ -32,7 +32,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.124 2008/10/11 05:07:20 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.125 2008/12/12 05:35:11 jmorse Exp $"); #include "opt_compat_netbsd.h" @@ -505,6 +505,15 @@ usbd_interface2endpoint_descriptor(usbd_interface_handle iface, u_int8_t index) return (iface->endpoints[index].edesc); } +/* Some drivers may wish to abort requests on the default pipe, * + * but there is no mechanism for getting a handle on it. */ +usbd_status +usbd_abort_default_pipe(struct usbd_device *device) +{ + + return usbd_abort_pipe(device->default_pipe); +} + usbd_status usbd_abort_pipe(usbd_pipe_handle pipe) { diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index 7b14f9be0815..4b0396f8e1e7 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -1,4 +1,4 @@ -/* $NetBSD: usbdi.h,v 1.76 2008/04/28 20:24:01 martin Exp $ */ +/* $NetBSD: usbdi.h,v 1.77 2008/12/12 05:35:11 jmorse Exp $ */ /* $FreeBSD: src/sys/dev/usb/usbdi.h,v 1.18 1999/11/17 22:33:49 n_hibma Exp $ */ /* @@ -112,6 +112,7 @@ void usbd_get_xfer_status(usbd_xfer_handle, usbd_private_handle *, usb_endpoint_descriptor_t *usbd_interface2endpoint_descriptor (usbd_interface_handle, u_int8_t); usbd_status usbd_abort_pipe(usbd_pipe_handle); +usbd_status usbd_abort_default_pipe(usbd_device_handle); usbd_status usbd_clear_endpoint_stall(usbd_pipe_handle); usbd_status usbd_clear_endpoint_stall_async(usbd_pipe_handle); void usbd_clear_endpoint_toggle(usbd_pipe_handle);