summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2020-10-25 20:45:50 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-12-29 15:47:07 +0300
commit27d7769667a28e21477881a0839adb00e9859f34 (patch)
treee48d1752bfd768c634dea2a7d7d65e620fb56f39
parent73e61d798ea53c0a03414f926a9b0453e38debce (diff)
downloadlinux-27d7769667a28e21477881a0839adb00e9859f34.tar.xz
USB: serial: keyspan_pda: fix write-wakeup use-after-free
commit 37faf50615412947868c49aee62f68233307f4e4 upstream. The driver's deferred write wakeup was never flushed on disconnect, something which could lead to the driver port data being freed while the wakeup work is still scheduled. Fix this by using the usb-serial write wakeup which gets cancelled properly on disconnect. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Acked-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Johan Hovold <johan@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/serial/keyspan_pda.c17
1 files changed, 3 insertions, 14 deletions
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index f4e5267f54d8..dde2fbb51b61 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -47,8 +47,7 @@
struct keyspan_pda_private {
int tx_room;
int tx_throttled;
- struct work_struct wakeup_work;
- struct work_struct unthrottle_work;
+ struct work_struct unthrottle_work;
struct usb_serial *serial;
struct usb_serial_port *port;
};
@@ -101,15 +100,6 @@ static const struct usb_device_id id_table_fake_xircom[] = {
};
#endif
-static void keyspan_pda_wakeup_write(struct work_struct *work)
-{
- struct keyspan_pda_private *priv =
- container_of(work, struct keyspan_pda_private, wakeup_work);
- struct usb_serial_port *port = priv->port;
-
- tty_port_tty_wakeup(&port->port);
-}
-
static void keyspan_pda_request_unthrottle(struct work_struct *work)
{
struct keyspan_pda_private *priv =
@@ -187,7 +177,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
case 2: /* tx unthrottle interrupt */
priv->tx_throttled = 0;
/* queue up a wakeup at scheduler time */
- schedule_work(&priv->wakeup_work);
+ usb_serial_port_softint(port);
break;
default:
break;
@@ -567,7 +557,7 @@ static void keyspan_pda_write_bulk_callback(struct urb *urb)
priv = usb_get_serial_port_data(port);
/* queue up a wakeup at scheduler time */
- schedule_work(&priv->wakeup_work);
+ usb_serial_port_softint(port);
}
@@ -720,7 +710,6 @@ static int keyspan_pda_port_probe(struct usb_serial_port *port)
if (!priv)
return -ENOMEM;
- INIT_WORK(&priv->wakeup_work, keyspan_pda_wakeup_write);
INIT_WORK(&priv->unthrottle_work, keyspan_pda_request_unthrottle);
priv->serial = port->serial;
priv->port = port;