Skip to content

Commit

Permalink
USB: cdc-acm: Fix disconnect() vs close() race
Browse files Browse the repository at this point in the history
There's a race between the USB disconnect handler and the TTY close
handler which may cause the acm object to be freed while it's still
being used. This may lead to things like

http://article.gmane.org/gmane.linux.usb.general/54250

and

https://lkml.org/lkml/2011/5/29/64

This is the simplest fix I could come up with. Holding on to open_mutex
while closing the TTY device prevents acm_disconnect() from freeing the
acm object between acm->port.count drops to 0 and the TTY side of the
cleanups are finalized.

Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
Cc: Oliver Neukum <oliver@neukum.name>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Havard Skinnemoen authored and Greg Kroah-Hartman committed Nov 14, 2011
1 parent 60c71ca commit 5dc2470
Showing 1 changed file with 5 additions and 3 deletions.
8 changes: 5 additions & 3 deletions drivers/usb/class/cdc-acm.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,6 @@ static void acm_port_down(struct acm *acm)
{
int i;

mutex_lock(&open_mutex);
if (acm->dev) {
usb_autopm_get_interface(acm->control);
acm_set_control(acm, acm->ctrlout = 0);
Expand All @@ -551,14 +550,15 @@ static void acm_port_down(struct acm *acm)
acm->control->needs_remote_wakeup = 0;
usb_autopm_put_interface(acm->control);
}
mutex_unlock(&open_mutex);
}

static void acm_tty_hangup(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
tty_port_hangup(&acm->port);
mutex_lock(&open_mutex);
acm_port_down(acm);
mutex_unlock(&open_mutex);
}

static void acm_tty_close(struct tty_struct *tty, struct file *filp)
Expand All @@ -569,8 +569,9 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
shutdown */
if (!acm)
return;

mutex_lock(&open_mutex);
if (tty_port_close_start(&acm->port, tty, filp) == 0) {
mutex_lock(&open_mutex);
if (!acm->dev) {
tty_port_tty_set(&acm->port, NULL);
acm_tty_unregister(acm);
Expand All @@ -582,6 +583,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
acm_port_down(acm);
tty_port_close_end(&acm->port, tty);
tty_port_tty_set(&acm->port, NULL);
mutex_unlock(&open_mutex);
}

static int acm_tty_write(struct tty_struct *tty,
Expand Down

0 comments on commit 5dc2470

Please sign in to comment.