diff options
author | Johan Hovold <jhovold@gmail.com> | 2013-02-13 11:53:28 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-02-13 12:20:06 -0500 |
commit | b2ca699076573c94fee9a73cb0d8645383b602a0 (patch) | |
tree | b9579ce8ed1511a5b3a234b03392b3c095de9231 /drivers/usb/serial/ftdi_sio.c | |
parent | cd565279e51bedee1b2988e84f9b3bef485adeb6 (diff) |
USB: serial: fix null-pointer dereferences on disconnect
Make sure serial-driver dtr_rts is called with disc_mutex held after
checking the disconnected flag.
Due to a bug in the tty layer, dtr_rts may get called after a device has
been disconnected and the tty-device unregistered. Some drivers have had
individual checks for disconnect to make sure the disconnected interface
was not accessed, but this should really be handled in usb-serial core
(at least until the long-standing tty-bug has been fixed).
Note that the problem has been made more acute with commit 0998d0631001
("device-core: Ensure drvdata = NULL when no driver is bound") as the
port data is now also NULL when dtr_rts is called resulting in further
oopses.
Reported-by: Chris Ruehl <chris.ruehl@gtsys.com.hk>
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/ftdi_sio.c')
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 20 |
1 files changed, 9 insertions, 11 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 90ceef1776c3..d07fccf3bab5 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -1886,24 +1886,22 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on) | |||
1886 | { | 1886 | { |
1887 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 1887 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
1888 | 1888 | ||
1889 | mutex_lock(&port->serial->disc_mutex); | 1889 | /* Disable flow control */ |
1890 | if (!port->serial->disconnected) { | 1890 | if (!on) { |
1891 | /* Disable flow control */ | 1891 | if (usb_control_msg(port->serial->dev, |
1892 | if (!on && usb_control_msg(port->serial->dev, | ||
1893 | usb_sndctrlpipe(port->serial->dev, 0), | 1892 | usb_sndctrlpipe(port->serial->dev, 0), |
1894 | FTDI_SIO_SET_FLOW_CTRL_REQUEST, | 1893 | FTDI_SIO_SET_FLOW_CTRL_REQUEST, |
1895 | FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, | 1894 | FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, |
1896 | 0, priv->interface, NULL, 0, | 1895 | 0, priv->interface, NULL, 0, |
1897 | WDR_TIMEOUT) < 0) { | 1896 | WDR_TIMEOUT) < 0) { |
1898 | dev_err(&port->dev, "error from flowcontrol urb\n"); | 1897 | dev_err(&port->dev, "error from flowcontrol urb\n"); |
1899 | } | 1898 | } |
1900 | /* drop RTS and DTR */ | ||
1901 | if (on) | ||
1902 | set_mctrl(port, TIOCM_DTR | TIOCM_RTS); | ||
1903 | else | ||
1904 | clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); | ||
1905 | } | 1899 | } |
1906 | mutex_unlock(&port->serial->disc_mutex); | 1900 | /* drop RTS and DTR */ |
1901 | if (on) | ||
1902 | set_mctrl(port, TIOCM_DTR | TIOCM_RTS); | ||
1903 | else | ||
1904 | clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); | ||
1907 | } | 1905 | } |
1908 | 1906 | ||
1909 | /* | 1907 | /* |