Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b68f2fb9 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds
Browse files

tty: Fix a USB serial crash/scribble



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: default avatarDaniel Mack <daniel@caiaq.de>
Signed-off-by: default avatarAlan Cox <alan@linux.intel.com>
Tested-by: default avatarDaniel Mack <daniel@caiaq.de>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 6a31d4ae
Loading
Loading
Loading
Loading
+18 −1
Original line number Original line Diff line number Diff line
@@ -340,6 +340,22 @@ static void serial_close(struct tty_struct *tty, struct file *filp)


	dbg("%s - port %d", __func__, port->number);
	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)
	if (tty_port_close_start(&port->port, tty, filp) == 0)
		return;
		return;
@@ -355,7 +371,8 @@ static void serial_hangup(struct tty_struct *tty)
	struct usb_serial_port *port = tty->driver_data;
	struct usb_serial_port *port = tty->driver_data;
	serial_do_down(port);
	serial_do_down(port);
	tty_port_hangup(&port->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,
static int serial_write(struct tty_struct *tty, const unsigned char *buf,