mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-06-02 02:52:20 -04:00
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
This commit is contained in:
@@ -194,6 +194,9 @@ static void belkin_sa_read_int_callback(struct urb *urb)
|
||||
|
||||
usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
|
||||
|
||||
if (urb->actual_length < BELKIN_SA_MSR_INDEX + 1)
|
||||
goto exit;
|
||||
|
||||
/* Handle known interrupt data */
|
||||
/* ignore data[0] and data[1] */
|
||||
|
||||
|
||||
@@ -445,6 +445,14 @@ static int cypress_generic_port_probe(struct usb_serial_port *port)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* The buffer must be large enough for the one or two-byte header (and
|
||||
* following data), but assume anything smaller than eight bytes is
|
||||
* broken.
|
||||
*/
|
||||
if (port->interrupt_out_size < 8)
|
||||
return -EINVAL;
|
||||
|
||||
priv = kzalloc_obj(struct cypress_private);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
@@ -1017,8 +1025,8 @@ static void cypress_read_int_callback(struct urb *urb)
|
||||
char tty_flag = TTY_NORMAL;
|
||||
int bytes = 0;
|
||||
int result;
|
||||
int i = 0;
|
||||
int status = urb->status;
|
||||
int i;
|
||||
|
||||
switch (status) {
|
||||
case 0: /* success */
|
||||
@@ -1056,22 +1064,32 @@ static void cypress_read_int_callback(struct urb *urb)
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
result = urb->actual_length;
|
||||
i = 0;
|
||||
switch (priv->pkt_fmt) {
|
||||
default:
|
||||
case packet_format_1:
|
||||
/* This is for the CY7C64013... */
|
||||
if (result < 2)
|
||||
break;
|
||||
priv->current_status = data[0] & 0xF8;
|
||||
bytes = data[1] + 2;
|
||||
i = 2;
|
||||
break;
|
||||
case packet_format_2:
|
||||
/* This is for the CY7C63743... */
|
||||
if (result < 1)
|
||||
break;
|
||||
priv->current_status = data[0] & 0xF8;
|
||||
bytes = (data[0] & 0x07) + 1;
|
||||
i = 1;
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
if (i == 0) {
|
||||
dev_dbg(dev, "%s - short packet received: %d bytes\n",
|
||||
__func__, result);
|
||||
goto continue_read;
|
||||
}
|
||||
if (result < bytes) {
|
||||
dev_dbg(dev,
|
||||
"%s - wrong packet size - received %d bytes but packet said %d bytes\n",
|
||||
|
||||
@@ -1229,15 +1229,34 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num)
|
||||
static int digi_startup(struct usb_serial *serial)
|
||||
{
|
||||
struct digi_serial *serial_priv;
|
||||
int oob_port_num;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* The port bulk-out buffers must be large enough for header and
|
||||
* buffered data.
|
||||
*/
|
||||
for (i = 0; i < serial->type->num_ports; i++) {
|
||||
if (serial->port[i]->bulk_out_size < DIGI_OUT_BUF_SIZE + 2)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The OOB port bulk-out buffer must be large enough for the two
|
||||
* commands in digi_set_modem_signals().
|
||||
*/
|
||||
oob_port_num = serial->type->num_ports;
|
||||
if (serial->port[oob_port_num]->bulk_out_size < 8)
|
||||
return -EINVAL;
|
||||
|
||||
serial_priv = kzalloc_obj(*serial_priv);
|
||||
if (!serial_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&serial_priv->ds_serial_lock);
|
||||
serial_priv->ds_oob_port_num = serial->type->num_ports;
|
||||
serial_priv->ds_oob_port = serial->port[serial_priv->ds_oob_port_num];
|
||||
serial_priv->ds_oob_port_num = oob_port_num;
|
||||
serial_priv->ds_oob_port = serial->port[oob_port_num];
|
||||
|
||||
ret = digi_port_init(serial_priv->ds_oob_port,
|
||||
serial_priv->ds_oob_port_num);
|
||||
|
||||
@@ -1187,6 +1187,10 @@ static void usa49wg_indat_callback(struct urb *urb)
|
||||
len = 0;
|
||||
|
||||
while (i < urb->actual_length) {
|
||||
if (urb->actual_length - i < 3) {
|
||||
dev_warn_ratelimited(&urb->dev->dev, "malformed indat packet\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check port number from message */
|
||||
if (data[i] >= serial->num_ports) {
|
||||
|
||||
@@ -378,6 +378,7 @@ static int mct_u232_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct usb_serial *serial = port->serial;
|
||||
struct mct_u232_private *priv;
|
||||
u16 pid;
|
||||
|
||||
/* check first to simplify error handling */
|
||||
if (!serial->port[1] || !serial->port[1]->interrupt_in_urb) {
|
||||
@@ -385,6 +386,16 @@ static int mct_u232_port_probe(struct usb_serial_port *port)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compensate for a hardware bug: although the Sitecom U232-P25
|
||||
* device reports a maximum output packet size of 32 bytes,
|
||||
* it seems to be able to accept only 16 bytes (and that's what
|
||||
* SniffUSB says too...)
|
||||
*/
|
||||
pid = le16_to_cpu(serial->dev->descriptor.idProduct);
|
||||
if (pid == MCT_U232_SITECOM_PID)
|
||||
port->bulk_out_size = min(16, port->bulk_out_size);
|
||||
|
||||
priv = kzalloc_obj(*priv);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
@@ -410,7 +421,6 @@ static void mct_u232_port_remove(struct usb_serial_port *port)
|
||||
|
||||
static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||
{
|
||||
struct usb_serial *serial = port->serial;
|
||||
struct mct_u232_private *priv = usb_get_serial_port_data(port);
|
||||
int retval = 0;
|
||||
unsigned int control_state;
|
||||
@@ -418,15 +428,6 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||
unsigned char last_lcr;
|
||||
unsigned char last_msr;
|
||||
|
||||
/* Compensate for a hardware bug: although the Sitecom U232-P25
|
||||
* device reports a maximum output packet size of 32 bytes,
|
||||
* it seems to be able to accept only 16 bytes (and that's what
|
||||
* SniffUSB says too...)
|
||||
*/
|
||||
if (le16_to_cpu(serial->dev->descriptor.idProduct)
|
||||
== MCT_U232_SITECOM_PID)
|
||||
port->bulk_out_size = 16;
|
||||
|
||||
/* Do a defined restart: the normal serial device seems to
|
||||
* always turn on DTR and RTS here, so do the same. I'm not
|
||||
* 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)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (urb->actual_length < 2) {
|
||||
dev_warn_ratelimited(&port->dev, "short interrupt-in packet\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* The interrupt-in pipe signals exceptional conditions (modem line
|
||||
* signal changes and errors). data[0] holds MSR, data[1] holds LSR.
|
||||
|
||||
@@ -962,6 +962,14 @@ static int mxuport_calc_num_ports(struct usb_serial *serial,
|
||||
*/
|
||||
BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_out) < 16);
|
||||
|
||||
/*
|
||||
* The bulk-out buffers must be large enough for the four-byte header
|
||||
* (and following data), but assume anything smaller than eight bytes
|
||||
* is broken.
|
||||
*/
|
||||
if (usb_endpoint_maxp(epds->bulk_out[0]) < 8)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 1; i < num_ports; ++i)
|
||||
epds->bulk_out[i] = epds->bulk_out[0];
|
||||
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
/* This one seems to be a re-branded ZyXEL device */
|
||||
#define BT_IGNITIONPRO_ID 0x2000
|
||||
|
||||
#define OMNINET_HEADERLEN 4
|
||||
#define OMNINET_BULKOUTSIZE 64
|
||||
#define OMNINET_PAYLOADSIZE (OMNINET_BULKOUTSIZE - OMNINET_HEADERLEN)
|
||||
|
||||
/* function prototypes */
|
||||
static void omninet_process_read_urb(struct urb *urb);
|
||||
static int omninet_prepare_write_buffer(struct usb_serial_port *port,
|
||||
@@ -54,6 +58,7 @@ static struct usb_serial_driver zyxel_omninet_device = {
|
||||
.description = "ZyXEL - omni.net usb",
|
||||
.id_table = id_table,
|
||||
.num_bulk_out = 2,
|
||||
.bulk_out_size = OMNINET_BULKOUTSIZE,
|
||||
.calc_num_ports = omninet_calc_num_ports,
|
||||
.port_probe = omninet_port_probe,
|
||||
.port_remove = omninet_port_remove,
|
||||
@@ -130,10 +135,6 @@ static void omninet_port_remove(struct usb_serial_port *port)
|
||||
kfree(od);
|
||||
}
|
||||
|
||||
#define OMNINET_HEADERLEN 4
|
||||
#define OMNINET_BULKOUTSIZE 64
|
||||
#define OMNINET_PAYLOADSIZE (OMNINET_BULKOUTSIZE - OMNINET_HEADERLEN)
|
||||
|
||||
static void omninet_process_read_urb(struct urb *urb)
|
||||
{
|
||||
struct usb_serial_port *port = urb->context;
|
||||
|
||||
@@ -2450,6 +2450,12 @@ static const struct usb_device_id option_ids[] = {
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x30) }, /* MeiG Smart SRM825WN (Diag) */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x40) }, /* MeiG Smart SRM825WN (AT) */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x60) }, /* MeiG Smart SRM825WN (NMEA) */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d63, 0xff, 0xff, 0x30) }, /* MeiG SRM813Q (Diag) */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d63, 0xff, 0xff, 0x40) }, /* MeiG SRM813Q (AT) */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d64, 0xff, 0xff, 0x30) }, /* MeiG SRM813Q (Diag) */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d64, 0xff, 0xff, 0x40) }, /* MeiG SRM813Q (AT) */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d64, 0xff, 0xff, 0x60) }, /* MeiG SRM813Q (NMEA) */
|
||||
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */
|
||||
@@ -2470,7 +2476,8 @@ static const struct usb_device_id option_ids[] = {
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x0302, 0xff) }, /* Rolling RW101R-GL (laptop MBIM) */
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x0802, 0xff), /* Rolling RW350-GL (laptop MBIM) */
|
||||
.driver_info = RSVD(5) },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff) }, /* Rolling RW135R-GL (laptop MBIM) */
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff), /* Rolling RW135R-GL (laptop MBIM) */
|
||||
.driver_info = RSVD(5) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WWD for Global */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0x00, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x40) },
|
||||
|
||||
@@ -259,6 +259,7 @@ static int safe_prepare_write_buffer(struct usb_serial_port *port,
|
||||
static int safe_startup(struct usb_serial *serial)
|
||||
{
|
||||
struct usb_interface_descriptor *desc;
|
||||
int bulk_out_size;
|
||||
|
||||
if (serial->dev->descriptor.bDeviceClass != CDC_DEVICE_CLASS)
|
||||
return -ENODEV;
|
||||
@@ -279,6 +280,16 @@ static int safe_startup(struct usb_serial *serial)
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The bulk-out buffer needs to be large enough for the two-byte
|
||||
* trailer in safe mode, but assume anything smaller than eight bytes
|
||||
* is broken.
|
||||
*/
|
||||
bulk_out_size = serial->port[0]->bulk_out_size;
|
||||
if (bulk_out_size > 0 && bulk_out_size < 8)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user