USB: ti_usb_3410_5052: fix use-after-free in TIOCMIWAIT
authorJohan Hovold <jhovold@gmail.com>
Tue, 19 Mar 2013 08:21:26 +0000 (09:21 +0100)
committerBen Hutchings <ben@decadent.org.uk>
Thu, 25 Apr 2013 19:25:30 +0000 (20:25 +0100)
commit fc98ab873aa3dbe783ce56a2ffdbbe7c7609521a upstream.

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.

Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/usb/serial/ti_usb_3410_5052.c

index 2856474..4b805be 100644 (file)
@@ -75,7 +75,6 @@ struct ti_port {
        int                     tp_flags;
        int                     tp_closing_wait;/* in .01 secs */
        struct async_icount     tp_icount;
-       wait_queue_head_t       tp_msr_wait;    /* wait for msr change */
        wait_queue_head_t       tp_write_wait;
        struct ti_device        *tp_tdev;
        struct usb_serial_port  *tp_port;
@@ -447,7 +446,6 @@ static int ti_startup(struct usb_serial *serial)
                tport->tp_uart_base_addr = (i == 0 ?
                                TI_UART1_BASE_ADDR : TI_UART2_BASE_ADDR);
                tport->tp_closing_wait = closing_wait;
-               init_waitqueue_head(&tport->tp_msr_wait);
                init_waitqueue_head(&tport->tp_write_wait);
                if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE,
                                                                GFP_KERNEL)) {
@@ -848,9 +846,13 @@ static int ti_ioctl(struct tty_struct *tty,
                dbg("%s - (%d) TIOCMIWAIT", __func__, port->number);
                cprev = tport->tp_icount;
                while (1) {
-                       interruptible_sleep_on(&tport->tp_msr_wait);
+                       interruptible_sleep_on(&port->delta_msr_wait);
                        if (signal_pending(current))
                                return -ERESTARTSYS;
+
+                       if (port->serial->disconnected)
+                               return -EIO;
+
                        cnow = tport->tp_icount;
                        if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
                            cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
@@ -1481,7 +1483,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
                        icount->dcd++;
                if (msr & TI_MSR_DELTA_RI)
                        icount->rng++;
-               wake_up_interruptible(&tport->tp_msr_wait);
+               wake_up_interruptible(&tport->tp_port->delta_msr_wait);
                spin_unlock_irqrestore(&tport->tp_lock, flags);
        }