aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2013-03-19 04:21:22 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-21 18:59:05 -0400
commit40509ca982c00c4b70fc00be887509feca0bff15 (patch)
tree3e2bd8f1336ea2690086bb596e6d87bc90420955
parent8edfdab37157d2683e51b8be5d3d5697f66a9f7b (diff)
USB: pl2303: 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/pl2303.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 54adc9125e5c..3b10018d89a3 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -139,7 +139,6 @@ struct pl2303_serial_private {
139 139
140struct pl2303_private { 140struct pl2303_private {
141 spinlock_t lock; 141 spinlock_t lock;
142 wait_queue_head_t delta_msr_wait;
143 u8 line_control; 142 u8 line_control;
144 u8 line_status; 143 u8 line_status;
145}; 144};
@@ -233,7 +232,6 @@ static int pl2303_port_probe(struct usb_serial_port *port)
233 return -ENOMEM; 232 return -ENOMEM;
234 233
235 spin_lock_init(&priv->lock); 234 spin_lock_init(&priv->lock);
236 init_waitqueue_head(&priv->delta_msr_wait);
237 235
238 usb_set_serial_port_data(port, priv); 236 usb_set_serial_port_data(port, priv);
239 237
@@ -607,11 +605,14 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
607 spin_unlock_irqrestore(&priv->lock, flags); 605 spin_unlock_irqrestore(&priv->lock, flags);
608 606
609 while (1) { 607 while (1) {
610 interruptible_sleep_on(&priv->delta_msr_wait); 608 interruptible_sleep_on(&port->delta_msr_wait);
611 /* see if a signal did it */ 609 /* see if a signal did it */
612 if (signal_pending(current)) 610 if (signal_pending(current))
613 return -ERESTARTSYS; 611 return -ERESTARTSYS;
614 612
613 if (port->serial->disconnected)
614 return -EIO;
615
615 spin_lock_irqsave(&priv->lock, flags); 616 spin_lock_irqsave(&priv->lock, flags);
616 status = priv->line_status; 617 status = priv->line_status;
617 spin_unlock_irqrestore(&priv->lock, flags); 618 spin_unlock_irqrestore(&priv->lock, flags);
@@ -719,7 +720,7 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
719 spin_unlock_irqrestore(&priv->lock, flags); 720 spin_unlock_irqrestore(&priv->lock, flags);
720 if (priv->line_status & UART_BREAK_ERROR) 721 if (priv->line_status & UART_BREAK_ERROR)
721 usb_serial_handle_break(port); 722 usb_serial_handle_break(port);
722 wake_up_interruptible(&priv->delta_msr_wait); 723 wake_up_interruptible(&port->delta_msr_wait);
723 724
724 tty = tty_port_tty_get(&port->port); 725 tty = tty_port_tty_get(&port->port);
725 if (!tty) 726 if (!tty)
@@ -783,7 +784,7 @@ static void pl2303_process_read_urb(struct urb *urb)
783 line_status = priv->line_status; 784 line_status = priv->line_status;
784 priv->line_status &= ~UART_STATE_TRANSIENT_MASK; 785 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
785 spin_unlock_irqrestore(&priv->lock, flags); 786 spin_unlock_irqrestore(&priv->lock, flags);
786 wake_up_interruptible(&priv->delta_msr_wait); 787 wake_up_interruptible(&port->delta_msr_wait);
787 788
788 if (!urb->actual_length) 789 if (!urb->actual_length)
789 return; 790 return;