Skip to content

Commit

Permalink
USB: serial: keyspan_pda: fix write-wakeup use-after-free
Browse files Browse the repository at this point in the history
commit 37faf50 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: 1da177e ("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>
  • Loading branch information
jhovold authored and gregkh committed Dec 30, 2020
1 parent a07b690 commit f99817a
Showing 1 changed file with 3 additions and 14 deletions.
17 changes: 3 additions & 14 deletions drivers/usb/serial/keyspan_pda.c
Expand Up @@ -43,8 +43,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;
};
Expand Down Expand Up @@ -97,15 +96,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 =
Expand Down Expand Up @@ -183,7 +173,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;
Expand Down Expand Up @@ -563,7 +553,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);
}


Expand Down Expand Up @@ -716,7 +706,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;
Expand Down

0 comments on commit f99817a

Please sign in to comment.