2009-07-22 09:41:48

by Alan

[permalink] [raw]
Subject: [PATCH] tty: Fix a USB serial crash/scribble

See if this one looks sensible. It does leave a tiny race window but that
semes wiser than hacking up the tty kref_put path in the middle of an -rc
series.

Thanks to Daniel and Alan Stern for chasing this down and getting traces. Also
to Daniel for being persistent when I took it as a random odd "only seen by one
user" error which it wasn't.

---

From: Alan Cox <[email protected]>

The port lock is used to protect the port state. However the port structure
is freed on a hangup, then the lock taken on a close. The right fix is to
drop the port on tty->shutdown() but we can't yet do that due to sleep v
non-sleeping rules. Instead do the next best thing and fix it up when we are
not in -rc season.

Reported-by: Daniel Mack <[email protected]>
Signed-off-by: Alan Cox <[email protected]>
---

drivers/usb/serial/usb-serial.c | 19 ++++++++++++++++++-
1 files changed, 18 insertions(+), 1 deletions(-)


diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index bd7581b..228d77c 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -340,6 +340,22 @@ static void serial_close(struct tty_struct *tty, struct file *filp)

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

+ /* FIXME:
+ This leaves a very narrow race. Really we should do the
+ serial_do_free() on tty->shutdown(), but tty->shutdown can
+ be called from IRQ context and serial_do_free can sleep.
+
+ The right fix is probably to make the tty free (which is rare)
+ and thus tty->shutdown() occur via a work queue and simplify all
+ the drivers that use it.
+ */
+ if (tty_hung_up_p(filp)) {
+ /* serial_hangup already called serial_down at this point.
+ Another user may have already reopened the port but
+ serial_do_free is refcounted */
+ serial_do_free(port);
+ return;
+ }

if (tty_port_close_start(&port->port, tty, filp) == 0)
return;
@@ -355,7 +371,8 @@ static void serial_hangup(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
serial_do_down(port);
tty_port_hangup(&port->port);
- serial_do_free(port);
+ /* We must not free port yet - the USB serial layer depends on it's
+ continued existence */
}

static int serial_write(struct tty_struct *tty, const unsigned char *buf,


2009-07-22 10:16:39

by Daniel Mack

[permalink] [raw]
Subject: Re: [PATCH] tty: Fix a USB serial crash/scribble

On Wed, Jul 22, 2009 at 10:39:51AM +0100, Alan Cox wrote:
> See if this one looks sensible. It does leave a tiny race window but that
> semes wiser than hacking up the tty kref_put path in the middle of an -rc
> series.
>
> Thanks to Daniel and Alan Stern for chasing this down and getting traces. Also
> to Daniel for being persistent when I took it as a random odd "only seen by one
> user" error which it wasn't.

Thanks Alan for your patience. You know the tty layer well which I have
no clue of, so I missed the bits in the close callback.

I tested your patch and can confirm it fixes the problem for me.

Daniel



> The port lock is used to protect the port state. However the port structure
> is freed on a hangup, then the lock taken on a close. The right fix is to
> drop the port on tty->shutdown() but we can't yet do that due to sleep v
> non-sleeping rules. Instead do the next best thing and fix it up when we are
> not in -rc season.
>
> Reported-by: Daniel Mack <[email protected]>
> Signed-off-by: Alan Cox <[email protected]>

Tested-by: Daniel Mack <[email protected]>


> ---
>
> drivers/usb/serial/usb-serial.c | 19 ++++++++++++++++++-
> 1 files changed, 18 insertions(+), 1 deletions(-)
>
>
> diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
> index bd7581b..228d77c 100644
> --- a/drivers/usb/serial/usb-serial.c
> +++ b/drivers/usb/serial/usb-serial.c
> @@ -340,6 +340,22 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
>
> dbg("%s - port %d", __func__, port->number);
>
> + /* FIXME:
> + This leaves a very narrow race. Really we should do the
> + serial_do_free() on tty->shutdown(), but tty->shutdown can
> + be called from IRQ context and serial_do_free can sleep.
> +
> + The right fix is probably to make the tty free (which is rare)
> + and thus tty->shutdown() occur via a work queue and simplify all
> + the drivers that use it.
> + */
> + if (tty_hung_up_p(filp)) {
> + /* serial_hangup already called serial_down at this point.
> + Another user may have already reopened the port but
> + serial_do_free is refcounted */
> + serial_do_free(port);
> + return;
> + }
>
> if (tty_port_close_start(&port->port, tty, filp) == 0)
> return;
> @@ -355,7 +371,8 @@ static void serial_hangup(struct tty_struct *tty)
> struct usb_serial_port *port = tty->driver_data;
> serial_do_down(port);
> tty_port_hangup(&port->port);
> - serial_do_free(port);
> + /* We must not free port yet - the USB serial layer depends on it's
> + continued existence */
> }
>
> static int serial_write(struct tty_struct *tty, const unsigned char *buf,
>

2009-07-25 04:57:44

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] tty: Fix a USB serial crash/scribble

On Wed, Jul 22, 2009 at 12:16:31PM +0200, Daniel Mack wrote:
> On Wed, Jul 22, 2009 at 10:39:51AM +0100, Alan Cox wrote:
> > See if this one looks sensible. It does leave a tiny race window but that
> > semes wiser than hacking up the tty kref_put path in the middle of an -rc
> > series.
> >
> > Thanks to Daniel and Alan Stern for chasing this down and getting traces. Also
> > to Daniel for being persistent when I took it as a random odd "only seen by one
> > user" error which it wasn't.
>
> Thanks Alan for your patience. You know the tty layer well which I have
> no clue of, so I missed the bits in the close callback.
>
> I tested your patch and can confirm it fixes the problem for me.
>
> Daniel
>
>
>
> > The port lock is used to protect the port state. However the port structure
> > is freed on a hangup, then the lock taken on a close. The right fix is to
> > drop the port on tty->shutdown() but we can't yet do that due to sleep v
> > non-sleeping rules. Instead do the next best thing and fix it up when we are
> > not in -rc season.
> >
> > Reported-by: Daniel Mack <[email protected]>
> > Signed-off-by: Alan Cox <[email protected]>
>
> Tested-by: Daniel Mack <[email protected]>

Acked-by: Greg Kroah-Hartman <[email protected]>

Alan, do you want me to send this to Linus, or will you?

thanks,

greg k-h

2009-07-25 11:55:29

by Alan

[permalink] [raw]
Subject: Re: [PATCH] tty: Fix a USB serial crash/scribble

> Alan, do you want me to send this to Linus, or will you?

I sent it to him on the 22nd.

2009-07-25 16:56:35

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] tty: Fix a USB serial crash/scribble

On Sat, Jul 25, 2009 at 12:56:21PM +0100, Alan Cox wrote:
> > Alan, do you want me to send this to Linus, or will you?
>
> I sent it to him on the 22nd.

Doh, nevermind :)