aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2013-03-19 04:21:17 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-21 18:59:04 -0400
commit7b2459690584f239650a365f3411ba2ec1c6d1e0 (patch)
treeb258f1f160f2b464b2ae4abca1a894f4ff2560cf
parent333576255d4cfc53efd056aad438568184b36af6 (diff)
USB: io_ti: fix use-after-free in TIOCMIWAIT
Use the port wait queue and make sure to check the serial disconnected flag before accessing private port data after waking up. This is is needed as the private port data (including the wait queue itself) can be gone when waking up after a disconnect. Cc: stable <stable@vger.kernel.org> Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/serial/io_ti.c12
1 files changed, 6 insertions, 6 deletions
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index d7d3c0e7cd27..7777172206de 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -87,9 +87,6 @@ struct edgeport_port {
87 int close_pending; 87 int close_pending;
88 int lsr_event; 88 int lsr_event;
89 struct async_icount icount; 89 struct async_icount icount;
90 wait_queue_head_t delta_msr_wait; /* for handling sleeping while
91 waiting for msr change to
92 happen */
93 struct edgeport_serial *edge_serial; 90 struct edgeport_serial *edge_serial;
94 struct usb_serial_port *port; 91 struct usb_serial_port *port;
95 __u8 bUartMode; /* Port type, 0: RS232, etc. */ 92 __u8 bUartMode; /* Port type, 0: RS232, etc. */
@@ -1459,7 +1456,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
1459 icount->dcd++; 1456 icount->dcd++;
1460 if (msr & EDGEPORT_MSR_DELTA_RI) 1457 if (msr & EDGEPORT_MSR_DELTA_RI)
1461 icount->rng++; 1458 icount->rng++;
1462 wake_up_interruptible(&edge_port->delta_msr_wait); 1459 wake_up_interruptible(&edge_port->port->delta_msr_wait);
1463 } 1460 }
1464 1461
1465 /* Save the new modem status */ 1462 /* Save the new modem status */
@@ -1754,7 +1751,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
1754 dev = port->serial->dev; 1751 dev = port->serial->dev;
1755 1752
1756 memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount)); 1753 memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount));
1757 init_waitqueue_head(&edge_port->delta_msr_wait);
1758 1754
1759 /* turn off loopback */ 1755 /* turn off loopback */
1760 status = ti_do_config(edge_port, UMPC_SET_CLR_LOOPBACK, 0); 1756 status = ti_do_config(edge_port, UMPC_SET_CLR_LOOPBACK, 0);
@@ -2434,10 +2430,14 @@ static int edge_ioctl(struct tty_struct *tty,
2434 dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__); 2430 dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__);
2435 cprev = edge_port->icount; 2431 cprev = edge_port->icount;
2436 while (1) { 2432 while (1) {
2437 interruptible_sleep_on(&edge_port->delta_msr_wait); 2433 interruptible_sleep_on(&port->delta_msr_wait);
2438 /* see if a signal did it */ 2434 /* see if a signal did it */
2439 if (signal_pending(current)) 2435 if (signal_pending(current))
2440 return -ERESTARTSYS; 2436 return -ERESTARTSYS;
2437
2438 if (port->serial->disconnected)
2439 return -EIO;
2440
2441 cnow = edge_port->icount; 2441 cnow = edge_port->icount;
2442 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 2442 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2443 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) 2443 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)