aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2017-01-06 13:15:18 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-01-19 14:18:01 -0500
commit3ed1f6da3a179cde1ccb3d72fe8a0f1d169f9800 (patch)
treeec5e7a99540031ef8dadc36e12472e2071e9aaba
parent139556a98511929d0354389e5017d599dedf9498 (diff)
USB: serial: ch341: fix control-message error handling
commit 2d5a9c72d0c4ac73cf97f4b7814ed6c44b1e49ae upstream. 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") Signed-off-by: Johan Hovold <johan@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.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 0a2420063098..517671522fe8 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -99,6 +99,8 @@ static int ch341_control_out(struct usb_device *dev, u8 request,
99 r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, 99 r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
100 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 100 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
101 value, index, NULL, 0, DEFAULT_TIMEOUT); 101 value, index, NULL, 0, DEFAULT_TIMEOUT);
102 if (r < 0)
103 dev_err(&dev->dev, "failed to send control message: %d\n", r);
102 104
103 return r; 105 return r;
104} 106}
@@ -116,7 +118,20 @@ static int ch341_control_in(struct usb_device *dev,
116 r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, 118 r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
117 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 119 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
118 value, index, buf, bufsize, DEFAULT_TIMEOUT); 120 value, index, buf, bufsize, DEFAULT_TIMEOUT);
119 return r; 121 if (r < bufsize) {
122 if (r >= 0) {
123 dev_err(&dev->dev,
124 "short control message received (%d < %u)\n",
125 r, bufsize);
126 r = -EIO;
127 }
128
129 dev_err(&dev->dev, "failed to receive control message: %d\n",
130 r);
131 return r;
132 }
133
134 return 0;
120} 135}
121 136
122static int ch341_set_baudrate(struct usb_device *dev, 137static int ch341_set_baudrate(struct usb_device *dev,
@@ -158,9 +173,9 @@ static int ch341_set_handshake(struct usb_device *dev, u8 control)
158 173
159static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) 174static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
160{ 175{
176 const unsigned int size = 2;
161 char *buffer; 177 char *buffer;
162 int r; 178 int r;
163 const unsigned size = 8;
164 unsigned long flags; 179 unsigned long flags;
165 180
166 buffer = kmalloc(size, GFP_KERNEL); 181 buffer = kmalloc(size, GFP_KERNEL);
@@ -171,14 +186,9 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
171 if (r < 0) 186 if (r < 0)
172 goto out; 187 goto out;
173 188
174 /* setup the private status if available */ 189 spin_lock_irqsave(&priv->lock, flags);
175 if (r == 2) { 190 priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
176 r = 0; 191 spin_unlock_irqrestore(&priv->lock, flags);
177 spin_lock_irqsave(&priv->lock, flags);
178 priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
179 spin_unlock_irqrestore(&priv->lock, flags);
180 } else
181 r = -EPROTO;
182 192
183out: kfree(buffer); 193out: kfree(buffer);
184 return r; 194 return r;
@@ -188,9 +198,9 @@ out: kfree(buffer);
188 198
189static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) 199static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
190{ 200{
201 const unsigned int size = 2;
191 char *buffer; 202 char *buffer;
192 int r; 203 int r;
193 const unsigned size = 8;
194 204
195 buffer = kmalloc(size, GFP_KERNEL); 205 buffer = kmalloc(size, GFP_KERNEL);
196 if (!buffer) 206 if (!buffer)