aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2017-01-06 13:15:18 -0500
committerJohan Hovold <johan@kernel.org>2017-01-11 06:08:57 -0500
commit2d5a9c72d0c4ac73cf97f4b7814ed6c44b1e49ae (patch)
tree212f96bdaa6e7612082a3d02d8506ec656364f70
parent146cc8a17a3b4996f6805ee5c080e7101277c410 (diff)
USB: serial: ch341: fix control-message error handling
A short control transfer would currently fail to be detected, something which could lead to stale buffer data being used as valid input. Check for short transfers, and make sure to log any transfer errors. Note that this also avoids leaking heap data to user space (TIOCMGET) and the remote device (break control). Fixes: 6ce76104781a ("USB: Driver for CH341 USB-serial adaptor") Cc: stable <stable@vger.kernel.org> Signed-off-by: Johan Hovold <johan@kernel.org>
-rw-r--r--drivers/usb/serial/ch341.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 8d7b0847109b..95aa5233726c 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -113,6 +113,8 @@ static int ch341_control_out(struct usb_device *dev, u8 request,
113 r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, 113 r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
114 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 114 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
115 value, index, NULL, 0, DEFAULT_TIMEOUT); 115 value, index, NULL, 0, DEFAULT_TIMEOUT);
116 if (r < 0)
117 dev_err(&dev->dev, "failed to send control message: %d\n", r);
116 118
117 return r; 119 return r;
118} 120}
@@ -130,7 +132,20 @@ static int ch341_control_in(struct usb_device *dev,
130 r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, 132 r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
131 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 133 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
132 value, index, buf, bufsize, DEFAULT_TIMEOUT); 134 value, index, buf, bufsize, DEFAULT_TIMEOUT);
133 return r; 135 if (r < bufsize) {
136 if (r >= 0) {
137 dev_err(&dev->dev,
138 "short control message received (%d < %u)\n",
139 r, bufsize);
140 r = -EIO;
141 }
142
143 dev_err(&dev->dev, "failed to receive control message: %d\n",
144 r);
145 return r;
146 }
147
148 return 0;
134} 149}
135 150
136static int ch341_set_baudrate_lcr(struct usb_device *dev, 151static int ch341_set_baudrate_lcr(struct usb_device *dev,
@@ -181,9 +196,9 @@ static int ch341_set_handshake(struct usb_device *dev, u8 control)
181 196
182static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) 197static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
183{ 198{
199 const unsigned int size = 2;
184 char *buffer; 200 char *buffer;
185 int r; 201 int r;
186 const unsigned size = 8;
187 unsigned long flags; 202 unsigned long flags;
188 203
189 buffer = kmalloc(size, GFP_KERNEL); 204 buffer = kmalloc(size, GFP_KERNEL);
@@ -194,14 +209,9 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
194 if (r < 0) 209 if (r < 0)
195 goto out; 210 goto out;
196 211
197 /* setup the private status if available */ 212 spin_lock_irqsave(&priv->lock, flags);
198 if (r == 2) { 213 priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
199 r = 0; 214 spin_unlock_irqrestore(&priv->lock, flags);
200 spin_lock_irqsave(&priv->lock, flags);
201 priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
202 spin_unlock_irqrestore(&priv->lock, flags);
203 } else
204 r = -EPROTO;
205 215
206out: kfree(buffer); 216out: kfree(buffer);
207 return r; 217 return r;
@@ -211,9 +221,9 @@ out: kfree(buffer);
211 221
212static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) 222static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
213{ 223{
224 const unsigned int size = 2;
214 char *buffer; 225 char *buffer;
215 int r; 226 int r;
216 const unsigned size = 8;
217 227
218 buffer = kmalloc(size, GFP_KERNEL); 228 buffer = kmalloc(size, GFP_KERNEL);
219 if (!buffer) 229 if (!buffer)