Skip to content

Commit

Permalink
USB: stop abuse of intfdata in cypress_m8
Browse files Browse the repository at this point in the history
this driver uses usb_get_intfdata() == NULL as a test for disconnect().
You must not do that as this races with probe(). By the time you test
your erstwhile interface may already be somebody else's interface.
This fixes the close() method of cypress_m8 to use the recently introduced
flag and use locking against disconnect() where required in close().

Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Oliver Neukum authored and Greg Kroah-Hartman committed Feb 1, 2008
1 parent 0b3f5fe commit 9e3b1d8
Showing 1 changed file with 16 additions and 9 deletions.
25 changes: 16 additions & 9 deletions drivers/usb/serial/cypress_m8.c
Original file line number Diff line number Diff line change
Expand Up @@ -682,34 +682,40 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
{
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned int c_cflag;
unsigned long flags;
int bps;
long timeout;
wait_queue_t wait;

dbg("%s - port %d", __FUNCTION__, port->number);

/* wait for data to drain from buffer */
spin_lock_irqsave(&priv->lock, flags);
spin_lock_irq(&priv->lock);
timeout = CYPRESS_CLOSING_WAIT;
init_waitqueue_entry(&wait, current);
add_wait_queue(&port->tty->write_wait, &wait);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (cypress_buf_data_avail(priv->buf) == 0
|| timeout == 0 || signal_pending(current)
|| !usb_get_intfdata(port->serial->interface))
/* without mutex, allowed due to harmless failure mode */
|| port->serial->disconnected)
break;
spin_unlock_irqrestore(&priv->lock, flags);
spin_unlock_irq(&priv->lock);
timeout = schedule_timeout(timeout);
spin_lock_irqsave(&priv->lock, flags);
spin_lock_irq(&priv->lock);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&port->tty->write_wait, &wait);
/* clear out any remaining data in the buffer */
cypress_buf_clear(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);

spin_unlock_irq(&priv->lock);

/* writing is potentially harmful, lock must be taken */
mutex_lock(&port->serial->disc_mutex);
if (port->serial->disconnected) {
mutex_unlock(&port->serial->disc_mutex);
return;
}
/* wait for characters to drain from device */
bps = tty_get_baud_rate(port->tty);
if (bps > 1200)
Expand All @@ -727,17 +733,18 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
if (c_cflag & HUPCL) {
/* drop dtr and rts */
priv = usb_get_serial_port_data(port);
spin_lock_irqsave(&priv->lock, flags);
spin_lock_irq(&priv->lock);
priv->line_control = 0;
priv->cmd_ctrl = 1;
spin_unlock_irqrestore(&priv->lock, flags);
spin_unlock_irq(&priv->lock);
cypress_write(port, NULL, 0);
}
}

if (stats)
dev_info (&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
priv->bytes_in, priv->bytes_out, priv->cmd_count);
mutex_unlock(&port->serial->disc_mutex);
} /* cypress_close */


Expand Down

0 comments on commit 9e3b1d8

Please sign in to comment.