Skip to content

Commit 645d4ed

Browse files
committed
Merge tag 'usb-serial-7.1-rc5' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-linus
Johan writes: USB serial fixes for 7.1-rc5 Here are a number of fixes for memory corruption and information leaks due to missing endpoint and transfer sanity checks dating back to simpler times when we trusted our hardware. Included are also a fix for a recently added modem device id entry and some new modem devices ids. All but the last five commits have been in linux-next and with no reported issues. * tag 'usb-serial-7.1-rc5' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial: USB: serial: cypress_m8: validate interrupt packet headers USB: serial: safe_serial: fix memory corruption with small endpoint USB: serial: omninet: fix memory corruption with small endpoint USB: serial: mxuport: fix memory corruption with small endpoint USB: serial: cypress_m8: fix memory corruption with small endpoint USB: serial: option: add missing RSVD(5) flag for Rolling RW135R-GL USB: serial: option: add MeiG SRM813Q USB: serial: mct_u232: fix missing interrupt-in transfer sanity check USB: serial: mct_u232: fix memory corruption with small endpoint USB: serial: keyspan: fix missing indat transfer sanity check USB: serial: digi_acceleport: fix memory corruption with small endpoints USB: serial: belkin_sa: validate interrupt status length
2 parents 5eb0707 + 9f9bfc8 commit 645d4ed

9 files changed

Lines changed: 95 additions & 18 deletions

File tree

drivers/usb/serial/belkin_sa.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ static void belkin_sa_read_int_callback(struct urb *urb)
194194

195195
usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
196196

197+
if (urb->actual_length < BELKIN_SA_MSR_INDEX + 1)
198+
goto exit;
199+
197200
/* Handle known interrupt data */
198201
/* ignore data[0] and data[1] */
199202

drivers/usb/serial/cypress_m8.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,14 @@ static int cypress_generic_port_probe(struct usb_serial_port *port)
445445
return -ENODEV;
446446
}
447447

448+
/*
449+
* The buffer must be large enough for the one or two-byte header (and
450+
* following data), but assume anything smaller than eight bytes is
451+
* broken.
452+
*/
453+
if (port->interrupt_out_size < 8)
454+
return -EINVAL;
455+
448456
priv = kzalloc_obj(struct cypress_private);
449457
if (!priv)
450458
return -ENOMEM;
@@ -1017,8 +1025,8 @@ static void cypress_read_int_callback(struct urb *urb)
10171025
char tty_flag = TTY_NORMAL;
10181026
int bytes = 0;
10191027
int result;
1020-
int i = 0;
10211028
int status = urb->status;
1029+
int i;
10221030

10231031
switch (status) {
10241032
case 0: /* success */
@@ -1056,22 +1064,32 @@ static void cypress_read_int_callback(struct urb *urb)
10561064

10571065
spin_lock_irqsave(&priv->lock, flags);
10581066
result = urb->actual_length;
1067+
i = 0;
10591068
switch (priv->pkt_fmt) {
10601069
default:
10611070
case packet_format_1:
10621071
/* This is for the CY7C64013... */
1072+
if (result < 2)
1073+
break;
10631074
priv->current_status = data[0] & 0xF8;
10641075
bytes = data[1] + 2;
10651076
i = 2;
10661077
break;
10671078
case packet_format_2:
10681079
/* This is for the CY7C63743... */
1080+
if (result < 1)
1081+
break;
10691082
priv->current_status = data[0] & 0xF8;
10701083
bytes = (data[0] & 0x07) + 1;
10711084
i = 1;
10721085
break;
10731086
}
10741087
spin_unlock_irqrestore(&priv->lock, flags);
1088+
if (i == 0) {
1089+
dev_dbg(dev, "%s - short packet received: %d bytes\n",
1090+
__func__, result);
1091+
goto continue_read;
1092+
}
10751093
if (result < bytes) {
10761094
dev_dbg(dev,
10771095
"%s - wrong packet size - received %d bytes but packet said %d bytes\n",

drivers/usb/serial/digi_acceleport.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,15 +1229,34 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num)
12291229
static int digi_startup(struct usb_serial *serial)
12301230
{
12311231
struct digi_serial *serial_priv;
1232+
int oob_port_num;
12321233
int ret;
1234+
int i;
1235+
1236+
/*
1237+
* The port bulk-out buffers must be large enough for header and
1238+
* buffered data.
1239+
*/
1240+
for (i = 0; i < serial->type->num_ports; i++) {
1241+
if (serial->port[i]->bulk_out_size < DIGI_OUT_BUF_SIZE + 2)
1242+
return -EINVAL;
1243+
}
1244+
1245+
/*
1246+
* The OOB port bulk-out buffer must be large enough for the two
1247+
* commands in digi_set_modem_signals().
1248+
*/
1249+
oob_port_num = serial->type->num_ports;
1250+
if (serial->port[oob_port_num]->bulk_out_size < 8)
1251+
return -EINVAL;
12331252

12341253
serial_priv = kzalloc_obj(*serial_priv);
12351254
if (!serial_priv)
12361255
return -ENOMEM;
12371256

12381257
spin_lock_init(&serial_priv->ds_serial_lock);
1239-
serial_priv->ds_oob_port_num = serial->type->num_ports;
1240-
serial_priv->ds_oob_port = serial->port[serial_priv->ds_oob_port_num];
1258+
serial_priv->ds_oob_port_num = oob_port_num;
1259+
serial_priv->ds_oob_port = serial->port[oob_port_num];
12411260

12421261
ret = digi_port_init(serial_priv->ds_oob_port,
12431262
serial_priv->ds_oob_port_num);

drivers/usb/serial/keyspan.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,6 +1187,10 @@ static void usa49wg_indat_callback(struct urb *urb)
11871187
len = 0;
11881188

11891189
while (i < urb->actual_length) {
1190+
if (urb->actual_length - i < 3) {
1191+
dev_warn_ratelimited(&urb->dev->dev, "malformed indat packet\n");
1192+
break;
1193+
}
11901194

11911195
/* Check port number from message */
11921196
if (data[i] >= serial->num_ports) {

drivers/usb/serial/mct_u232.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -378,13 +378,24 @@ static int mct_u232_port_probe(struct usb_serial_port *port)
378378
{
379379
struct usb_serial *serial = port->serial;
380380
struct mct_u232_private *priv;
381+
u16 pid;
381382

382383
/* check first to simplify error handling */
383384
if (!serial->port[1] || !serial->port[1]->interrupt_in_urb) {
384385
dev_err(&port->dev, "expected endpoint missing\n");
385386
return -ENODEV;
386387
}
387388

389+
/*
390+
* Compensate for a hardware bug: although the Sitecom U232-P25
391+
* device reports a maximum output packet size of 32 bytes,
392+
* it seems to be able to accept only 16 bytes (and that's what
393+
* SniffUSB says too...)
394+
*/
395+
pid = le16_to_cpu(serial->dev->descriptor.idProduct);
396+
if (pid == MCT_U232_SITECOM_PID)
397+
port->bulk_out_size = min(16, port->bulk_out_size);
398+
388399
priv = kzalloc_obj(*priv);
389400
if (!priv)
390401
return -ENOMEM;
@@ -410,23 +421,13 @@ static void mct_u232_port_remove(struct usb_serial_port *port)
410421

411422
static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
412423
{
413-
struct usb_serial *serial = port->serial;
414424
struct mct_u232_private *priv = usb_get_serial_port_data(port);
415425
int retval = 0;
416426
unsigned int control_state;
417427
unsigned long flags;
418428
unsigned char last_lcr;
419429
unsigned char last_msr;
420430

421-
/* Compensate for a hardware bug: although the Sitecom U232-P25
422-
* device reports a maximum output packet size of 32 bytes,
423-
* it seems to be able to accept only 16 bytes (and that's what
424-
* SniffUSB says too...)
425-
*/
426-
if (le16_to_cpu(serial->dev->descriptor.idProduct)
427-
== MCT_U232_SITECOM_PID)
428-
port->bulk_out_size = 16;
429-
430431
/* Do a defined restart: the normal serial device seems to
431432
* always turn on DTR and RTS here, so do the same. I'm not
432433
* sure if this is really necessary. But it should not harm
@@ -543,6 +544,11 @@ static void mct_u232_read_int_callback(struct urb *urb)
543544
goto exit;
544545
}
545546

547+
if (urb->actual_length < 2) {
548+
dev_warn_ratelimited(&port->dev, "short interrupt-in packet\n");
549+
goto exit;
550+
}
551+
546552
/*
547553
* The interrupt-in pipe signals exceptional conditions (modem line
548554
* signal changes and errors). data[0] holds MSR, data[1] holds LSR.

drivers/usb/serial/mxuport.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,14 @@ static int mxuport_calc_num_ports(struct usb_serial *serial,
962962
*/
963963
BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_out) < 16);
964964

965+
/*
966+
* The bulk-out buffers must be large enough for the four-byte header
967+
* (and following data), but assume anything smaller than eight bytes
968+
* is broken.
969+
*/
970+
if (usb_endpoint_maxp(epds->bulk_out[0]) < 8)
971+
return -EINVAL;
972+
965973
for (i = 1; i < num_ports; ++i)
966974
epds->bulk_out[i] = epds->bulk_out[0];
967975

drivers/usb/serial/omninet.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030
/* This one seems to be a re-branded ZyXEL device */
3131
#define BT_IGNITIONPRO_ID 0x2000
3232

33+
#define OMNINET_HEADERLEN 4
34+
#define OMNINET_BULKOUTSIZE 64
35+
#define OMNINET_PAYLOADSIZE (OMNINET_BULKOUTSIZE - OMNINET_HEADERLEN)
36+
3337
/* function prototypes */
3438
static void omninet_process_read_urb(struct urb *urb);
3539
static int omninet_prepare_write_buffer(struct usb_serial_port *port,
@@ -54,6 +58,7 @@ static struct usb_serial_driver zyxel_omninet_device = {
5458
.description = "ZyXEL - omni.net usb",
5559
.id_table = id_table,
5660
.num_bulk_out = 2,
61+
.bulk_out_size = OMNINET_BULKOUTSIZE,
5762
.calc_num_ports = omninet_calc_num_ports,
5863
.port_probe = omninet_port_probe,
5964
.port_remove = omninet_port_remove,
@@ -130,10 +135,6 @@ static void omninet_port_remove(struct usb_serial_port *port)
130135
kfree(od);
131136
}
132137

133-
#define OMNINET_HEADERLEN 4
134-
#define OMNINET_BULKOUTSIZE 64
135-
#define OMNINET_PAYLOADSIZE (OMNINET_BULKOUTSIZE - OMNINET_HEADERLEN)
136-
137138
static void omninet_process_read_urb(struct urb *urb)
138139
{
139140
struct usb_serial_port *port = urb->context;

drivers/usb/serial/option.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2450,6 +2450,12 @@ static const struct usb_device_id option_ids[] = {
24502450
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x30) }, /* MeiG Smart SRM825WN (Diag) */
24512451
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x40) }, /* MeiG Smart SRM825WN (AT) */
24522452
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x60) }, /* MeiG Smart SRM825WN (NMEA) */
2453+
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d63, 0xff, 0xff, 0x30) }, /* MeiG SRM813Q (Diag) */
2454+
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d63, 0xff, 0xff, 0x40) }, /* MeiG SRM813Q (AT) */
2455+
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d64, 0xff, 0xff, 0x30) }, /* MeiG SRM813Q (Diag) */
2456+
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d64, 0xff, 0xff, 0x40) }, /* MeiG SRM813Q (AT) */
2457+
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d64, 0xff, 0xff, 0x60) }, /* MeiG SRM813Q (NMEA) */
2458+
24532459
{ USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */
24542460
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */
24552461
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */
@@ -2470,7 +2476,8 @@ static const struct usb_device_id option_ids[] = {
24702476
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x0302, 0xff) }, /* Rolling RW101R-GL (laptop MBIM) */
24712477
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x0802, 0xff), /* Rolling RW350-GL (laptop MBIM) */
24722478
.driver_info = RSVD(5) },
2473-
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff) }, /* Rolling RW135R-GL (laptop MBIM) */
2479+
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff), /* Rolling RW135R-GL (laptop MBIM) */
2480+
.driver_info = RSVD(5) },
24742481
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WWD for Global */
24752482
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0x00, 0x40) },
24762483
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x40) },

drivers/usb/serial/safe_serial.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ static int safe_prepare_write_buffer(struct usb_serial_port *port,
259259
static int safe_startup(struct usb_serial *serial)
260260
{
261261
struct usb_interface_descriptor *desc;
262+
int bulk_out_size;
262263

263264
if (serial->dev->descriptor.bDeviceClass != CDC_DEVICE_CLASS)
264265
return -ENODEV;
@@ -279,6 +280,16 @@ static int safe_startup(struct usb_serial *serial)
279280
default:
280281
return -EINVAL;
281282
}
283+
284+
/*
285+
* The bulk-out buffer needs to be large enough for the two-byte
286+
* trailer in safe mode, but assume anything smaller than eight bytes
287+
* is broken.
288+
*/
289+
bulk_out_size = serial->port[0]->bulk_out_size;
290+
if (bulk_out_size > 0 && bulk_out_size < 8)
291+
return -EINVAL;
292+
282293
return 0;
283294
}
284295

0 commit comments

Comments
 (0)