]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/3.7.10/usb-serial-fix-null-pointer-dereferences-on-disconnect.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.7.10 / usb-serial-fix-null-pointer-dereferences-on-disconnect.patch
1 From b2ca699076573c94fee9a73cb0d8645383b602a0 Mon Sep 17 00:00:00 2001
2 From: Johan Hovold <jhovold@gmail.com>
3 Date: Wed, 13 Feb 2013 17:53:28 +0100
4 Subject: USB: serial: fix null-pointer dereferences on disconnect
5
6 From: Johan Hovold <jhovold@gmail.com>
7
8 commit b2ca699076573c94fee9a73cb0d8645383b602a0 upstream.
9
10 Make sure serial-driver dtr_rts is called with disc_mutex held after
11 checking the disconnected flag.
12
13 Due to a bug in the tty layer, dtr_rts may get called after a device has
14 been disconnected and the tty-device unregistered. Some drivers have had
15 individual checks for disconnect to make sure the disconnected interface
16 was not accessed, but this should really be handled in usb-serial core
17 (at least until the long-standing tty-bug has been fixed).
18
19 Note that the problem has been made more acute with commit 0998d0631001
20 ("device-core: Ensure drvdata = NULL when no driver is bound") as the
21 port data is now also NULL when dtr_rts is called resulting in further
22 oopses.
23
24 Reported-by: Chris Ruehl <chris.ruehl@gtsys.com.hk>
25 Signed-off-by: Johan Hovold <jhovold@gmail.com>
26 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
27
28 ---
29 drivers/usb/serial/ftdi_sio.c | 20 +++++++++-----------
30 drivers/usb/serial/mct_u232.c | 22 +++++++++-------------
31 drivers/usb/serial/quatech2.c | 18 ++++++++----------
32 drivers/usb/serial/sierra.c | 8 +-------
33 drivers/usb/serial/ssu100.c | 19 ++++++++-----------
34 drivers/usb/serial/usb-serial.c | 14 ++++++++++++--
35 drivers/usb/serial/usb_wwan.c | 8 +++-----
36 7 files changed, 50 insertions(+), 59 deletions(-)
37
38 --- a/drivers/usb/serial/ftdi_sio.c
39 +++ b/drivers/usb/serial/ftdi_sio.c
40 @@ -1884,24 +1884,22 @@ static void ftdi_dtr_rts(struct usb_seri
41 {
42 struct ftdi_private *priv = usb_get_serial_port_data(port);
43
44 - mutex_lock(&port->serial->disc_mutex);
45 - if (!port->serial->disconnected) {
46 - /* Disable flow control */
47 - if (!on && usb_control_msg(port->serial->dev,
48 + /* Disable flow control */
49 + if (!on) {
50 + if (usb_control_msg(port->serial->dev,
51 usb_sndctrlpipe(port->serial->dev, 0),
52 FTDI_SIO_SET_FLOW_CTRL_REQUEST,
53 FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
54 0, priv->interface, NULL, 0,
55 WDR_TIMEOUT) < 0) {
56 - dev_err(&port->dev, "error from flowcontrol urb\n");
57 + dev_err(&port->dev, "error from flowcontrol urb\n");
58 }
59 - /* drop RTS and DTR */
60 - if (on)
61 - set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
62 - else
63 - clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
64 }
65 - mutex_unlock(&port->serial->disc_mutex);
66 + /* drop RTS and DTR */
67 + if (on)
68 + set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
69 + else
70 + clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
71 }
72
73 /*
74 --- a/drivers/usb/serial/mct_u232.c
75 +++ b/drivers/usb/serial/mct_u232.c
76 @@ -503,19 +503,15 @@ static void mct_u232_dtr_rts(struct usb_
77 unsigned int control_state;
78 struct mct_u232_private *priv = usb_get_serial_port_data(port);
79
80 - mutex_lock(&port->serial->disc_mutex);
81 - if (!port->serial->disconnected) {
82 - /* drop DTR and RTS */
83 - spin_lock_irq(&priv->lock);
84 - if (on)
85 - priv->control_state |= TIOCM_DTR | TIOCM_RTS;
86 - else
87 - priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
88 - control_state = priv->control_state;
89 - spin_unlock_irq(&priv->lock);
90 - mct_u232_set_modem_ctrl(port, control_state);
91 - }
92 - mutex_unlock(&port->serial->disc_mutex);
93 + spin_lock_irq(&priv->lock);
94 + if (on)
95 + priv->control_state |= TIOCM_DTR | TIOCM_RTS;
96 + else
97 + priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
98 + control_state = priv->control_state;
99 + spin_unlock_irq(&priv->lock);
100 +
101 + mct_u232_set_modem_ctrl(port, control_state);
102 }
103
104 static void mct_u232_close(struct usb_serial_port *port)
105 --- a/drivers/usb/serial/quatech2.c
106 +++ b/drivers/usb/serial/quatech2.c
107 @@ -947,19 +947,17 @@ static void qt2_dtr_rts(struct usb_seria
108 struct usb_device *dev = port->serial->dev;
109 struct qt2_port_private *port_priv = usb_get_serial_port_data(port);
110
111 - mutex_lock(&port->serial->disc_mutex);
112 - if (!port->serial->disconnected) {
113 - /* Disable flow control */
114 - if (!on && qt2_setregister(dev, port_priv->device_port,
115 + /* Disable flow control */
116 + if (!on) {
117 + if (qt2_setregister(dev, port_priv->device_port,
118 UART_MCR, 0) < 0)
119 dev_warn(&port->dev, "error from flowcontrol urb\n");
120 - /* drop RTS and DTR */
121 - if (on)
122 - update_mctrl(port_priv, TIOCM_DTR | TIOCM_RTS, 0);
123 - else
124 - update_mctrl(port_priv, 0, TIOCM_DTR | TIOCM_RTS);
125 }
126 - mutex_unlock(&port->serial->disc_mutex);
127 + /* drop RTS and DTR */
128 + if (on)
129 + update_mctrl(port_priv, TIOCM_DTR | TIOCM_RTS, 0);
130 + else
131 + update_mctrl(port_priv, 0, TIOCM_DTR | TIOCM_RTS);
132 }
133
134 static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch)
135 --- a/drivers/usb/serial/sierra.c
136 +++ b/drivers/usb/serial/sierra.c
137 @@ -861,19 +861,13 @@ static int sierra_open(struct tty_struct
138
139 static void sierra_dtr_rts(struct usb_serial_port *port, int on)
140 {
141 - struct usb_serial *serial = port->serial;
142 struct sierra_port_private *portdata;
143
144 portdata = usb_get_serial_port_data(port);
145 portdata->rts_state = on;
146 portdata->dtr_state = on;
147
148 - if (serial->dev) {
149 - mutex_lock(&serial->disc_mutex);
150 - if (!serial->disconnected)
151 - sierra_send_setup(port);
152 - mutex_unlock(&serial->disc_mutex);
153 - }
154 + sierra_send_setup(port);
155 }
156
157 static int sierra_startup(struct usb_serial *serial)
158 --- a/drivers/usb/serial/ssu100.c
159 +++ b/drivers/usb/serial/ssu100.c
160 @@ -508,19 +508,16 @@ static void ssu100_dtr_rts(struct usb_se
161 {
162 struct usb_device *dev = port->serial->dev;
163
164 - mutex_lock(&port->serial->disc_mutex);
165 - if (!port->serial->disconnected) {
166 - /* Disable flow control */
167 - if (!on &&
168 - ssu100_setregister(dev, 0, UART_MCR, 0) < 0)
169 + /* Disable flow control */
170 + if (!on) {
171 + if (ssu100_setregister(dev, 0, UART_MCR, 0) < 0)
172 dev_err(&port->dev, "error from flowcontrol urb\n");
173 - /* drop RTS and DTR */
174 - if (on)
175 - set_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
176 - else
177 - clear_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
178 }
179 - mutex_unlock(&port->serial->disc_mutex);
180 + /* drop RTS and DTR */
181 + if (on)
182 + set_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
183 + else
184 + clear_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
185 }
186
187 static void ssu100_update_msr(struct usb_serial_port *port, u8 msr)
188 --- a/drivers/usb/serial/usb-serial.c
189 +++ b/drivers/usb/serial/usb-serial.c
190 @@ -687,10 +687,20 @@ static int serial_carrier_raised(struct
191 static void serial_dtr_rts(struct tty_port *port, int on)
192 {
193 struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
194 - struct usb_serial_driver *drv = p->serial->type;
195 + struct usb_serial *serial = p->serial;
196 + struct usb_serial_driver *drv = serial->type;
197
198 - if (drv->dtr_rts)
199 + if (!drv->dtr_rts)
200 + return;
201 + /*
202 + * Work-around bug in the tty-layer which can result in dtr_rts
203 + * being called after a disconnect (and tty_unregister_device
204 + * has returned). Remove once bug has been squashed.
205 + */
206 + mutex_lock(&serial->disc_mutex);
207 + if (!serial->disconnected)
208 drv->dtr_rts(p, on);
209 + mutex_unlock(&serial->disc_mutex);
210 }
211
212 static const struct tty_port_operations serial_port_ops = {
213 --- a/drivers/usb/serial/usb_wwan.c
214 +++ b/drivers/usb/serial/usb_wwan.c
215 @@ -39,7 +39,6 @@
216
217 void usb_wwan_dtr_rts(struct usb_serial_port *port, int on)
218 {
219 - struct usb_serial *serial = port->serial;
220 struct usb_wwan_port_private *portdata;
221 struct usb_wwan_intf_private *intfdata;
222
223 @@ -49,12 +48,11 @@ void usb_wwan_dtr_rts(struct usb_serial_
224 return;
225
226 portdata = usb_get_serial_port_data(port);
227 - mutex_lock(&serial->disc_mutex);
228 + /* FIXME: locking */
229 portdata->rts_state = on;
230 portdata->dtr_state = on;
231 - if (serial->dev)
232 - intfdata->send_setup(port);
233 - mutex_unlock(&serial->disc_mutex);
234 +
235 + intfdata->send_setup(port);
236 }
237 EXPORT_SYMBOL(usb_wwan_dtr_rts);
238