aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/spcp8x5.c
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2013-03-19 04:21:24 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-21 18:59:05 -0400
commitdbcea7615d8d7d58f6ff49d2c5568113f70effe9 (patch)
tree47f06b36ddcc1a8b48288fd901e5073ab7a60bec /drivers/usb/serial/spcp8x5.c
parent69f87f40d2b98e8b4ab82a121fd2bd584690b887 (diff)
USB: spcp8x5: 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>
Diffstat (limited to 'drivers/usb/serial/spcp8x5.c')
-rw-r--r--drivers/usb/serial/spcp8x5.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index 91ff8e3bddbd..549ef68ff5fa 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -149,7 +149,6 @@ enum spcp8x5_type {
149struct spcp8x5_private { 149struct spcp8x5_private {
150 spinlock_t lock; 150 spinlock_t lock;
151 enum spcp8x5_type type; 151 enum spcp8x5_type type;
152 wait_queue_head_t delta_msr_wait;
153 u8 line_control; 152 u8 line_control;
154 u8 line_status; 153 u8 line_status;
155}; 154};
@@ -179,7 +178,6 @@ static int spcp8x5_port_probe(struct usb_serial_port *port)
179 return -ENOMEM; 178 return -ENOMEM;
180 179
181 spin_lock_init(&priv->lock); 180 spin_lock_init(&priv->lock);
182 init_waitqueue_head(&priv->delta_msr_wait);
183 priv->type = type; 181 priv->type = type;
184 182
185 usb_set_serial_port_data(port , priv); 183 usb_set_serial_port_data(port , priv);
@@ -475,7 +473,7 @@ static void spcp8x5_process_read_urb(struct urb *urb)
475 priv->line_status &= ~UART_STATE_TRANSIENT_MASK; 473 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
476 spin_unlock_irqrestore(&priv->lock, flags); 474 spin_unlock_irqrestore(&priv->lock, flags);
477 /* wake up the wait for termios */ 475 /* wake up the wait for termios */
478 wake_up_interruptible(&priv->delta_msr_wait); 476 wake_up_interruptible(&port->delta_msr_wait);
479 477
480 if (!urb->actual_length) 478 if (!urb->actual_length)
481 return; 479 return;
@@ -526,12 +524,15 @@ static int spcp8x5_wait_modem_info(struct usb_serial_port *port,
526 524
527 while (1) { 525 while (1) {
528 /* wake up in bulk read */ 526 /* wake up in bulk read */
529 interruptible_sleep_on(&priv->delta_msr_wait); 527 interruptible_sleep_on(&port->delta_msr_wait);
530 528
531 /* see if a signal did it */ 529 /* see if a signal did it */
532 if (signal_pending(current)) 530 if (signal_pending(current))
533 return -ERESTARTSYS; 531 return -ERESTARTSYS;
534 532
533 if (port->serial->disconnected)
534 return -EIO;
535
535 spin_lock_irqsave(&priv->lock, flags); 536 spin_lock_irqsave(&priv->lock, flags);
536 status = priv->line_status; 537 status = priv->line_status;
537 spin_unlock_irqrestore(&priv->lock, flags); 538 spin_unlock_irqrestore(&priv->lock, flags);