Skip to content

Commit

Permalink
Merge tag 'usb-serial-4.10-rc3' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/kernel/git/johan/usb-serial into usb-linus

Johan writes:

USB-serial fixes for v4.10-rc3

These fixes address a number of long-standing issues in various
USB-serial drivers which would lead to crashes should a malicious device
lack the expected endpoints.

Included are also a few related fixes, and a couple of unrelated ones
that were found during my survey (e.g. a memleak and a
sleep-while-atomic).

A compiler warning revealed an error-handling issue in the new f81534
driver which is also fixed.

Signed-off-by: Johan Hovold <johan@kernel.org>
  • Loading branch information
Greg Kroah-Hartman committed Jan 5, 2017
2 parents 29fc1aa + ef07993 commit c8d204b
Show file tree
Hide file tree
Showing 16 changed files with 167 additions and 58 deletions.
10 changes: 10 additions & 0 deletions drivers/usb/serial/cyberjack.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#define CYBERJACK_PRODUCT_ID 0x0100

/* Function prototypes */
static int cyberjack_attach(struct usb_serial *serial);
static int cyberjack_port_probe(struct usb_serial_port *port);
static int cyberjack_port_remove(struct usb_serial_port *port);
static int cyberjack_open(struct tty_struct *tty,
Expand Down Expand Up @@ -77,6 +78,7 @@ static struct usb_serial_driver cyberjack_device = {
.description = "Reiner SCT Cyberjack USB card reader",
.id_table = id_table,
.num_ports = 1,
.attach = cyberjack_attach,
.port_probe = cyberjack_port_probe,
.port_remove = cyberjack_port_remove,
.open = cyberjack_open,
Expand All @@ -100,6 +102,14 @@ struct cyberjack_private {
short wrsent; /* Data already sent */
};

static int cyberjack_attach(struct usb_serial *serial)
{
if (serial->num_bulk_out < serial->num_ports)
return -ENODEV;

return 0;
}

static int cyberjack_port_probe(struct usb_serial_port *port)
{
struct cyberjack_private *priv;
Expand Down
8 changes: 5 additions & 3 deletions drivers/usb/serial/f81534.c
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,7 @@ static int f81534_attach(struct usb_serial *serial)
static int f81534_port_probe(struct usb_serial_port *port)
{
struct f81534_port_private *port_priv;
int ret;

port_priv = devm_kzalloc(&port->dev, sizeof(*port_priv), GFP_KERNEL);
if (!port_priv)
Expand All @@ -1246,10 +1247,11 @@ static int f81534_port_probe(struct usb_serial_port *port)
mutex_init(&port_priv->mcr_mutex);

/* Assign logic-to-phy mapping */
port_priv->phy_num = f81534_logic_to_phy_port(port->serial, port);
if (port_priv->phy_num < 0 || port_priv->phy_num >= F81534_NUM_PORT)
return -ENODEV;
ret = f81534_logic_to_phy_port(port->serial, port);
if (ret < 0)
return ret;

port_priv->phy_num = ret;
usb_set_serial_port_data(port, port_priv);
dev_dbg(&port->dev, "%s: port_number: %d, phy_num: %d\n", __func__,
port->port_number, port_priv->phy_num);
Expand Down
1 change: 1 addition & 0 deletions drivers/usb/serial/garmin_gps.c
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,7 @@ static int garmin_write_bulk(struct usb_serial_port *port,
"%s - usb_submit_urb(write bulk) failed with status = %d\n",
__func__, status);
count = status;
kfree(buffer);
}

/* we are done with this urb, so let the host driver
Expand Down
5 changes: 5 additions & 0 deletions drivers/usb/serial/io_edgeport.c
Original file line number Diff line number Diff line change
Expand Up @@ -2751,6 +2751,11 @@ static int edge_startup(struct usb_serial *serial)
EDGE_COMPATIBILITY_MASK1,
EDGE_COMPATIBILITY_MASK2 };

if (serial->num_bulk_in < 1 || serial->num_interrupt_in < 1) {
dev_err(&serial->interface->dev, "missing endpoints\n");
return -ENODEV;
}

dev = serial->dev;

/* create our private serial structure */
Expand Down
22 changes: 17 additions & 5 deletions drivers/usb/serial/io_ti.c
Original file line number Diff line number Diff line change
Expand Up @@ -1499,16 +1499,15 @@ static int do_boot_mode(struct edgeport_serial *serial,

dev_dbg(dev, "%s - Download successful -- Device rebooting...\n", __func__);

/* return an error on purpose */
return -ENODEV;
return 1;
}

stayinbootmode:
/* Eprom is invalid or blank stay in boot mode */
dev_dbg(dev, "%s - STAYING IN BOOT MODE\n", __func__);
serial->product_info.TiMode = TI_MODE_BOOT;

return 0;
return 1;
}

static int ti_do_config(struct edgeport_port *port, int feature, int on)
Expand Down Expand Up @@ -2546,21 +2545,32 @@ static int edge_startup(struct usb_serial *serial)
int status;
u16 product_id;

/* Make sure we have the required endpoints when in download mode. */
if (serial->interface->cur_altsetting->desc.bNumEndpoints > 1) {
if (serial->num_bulk_in < serial->num_ports ||
serial->num_bulk_out < serial->num_ports)
return -ENODEV;
}

/* create our private serial structure */
edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
if (!edge_serial)
return -ENOMEM;

mutex_init(&edge_serial->es_lock);
edge_serial->serial = serial;
INIT_DELAYED_WORK(&edge_serial->heartbeat_work, edge_heartbeat_work);
usb_set_serial_data(serial, edge_serial);

status = download_fw(edge_serial);
if (status) {
if (status < 0) {
kfree(edge_serial);
return status;
}

if (status > 0)
return 1; /* bind but do not register any ports */

product_id = le16_to_cpu(
edge_serial->serial->dev->descriptor.idProduct);

Expand All @@ -2572,14 +2582,16 @@ static int edge_startup(struct usb_serial *serial)
}
}

INIT_DELAYED_WORK(&edge_serial->heartbeat_work, edge_heartbeat_work);
edge_heartbeat_schedule(edge_serial);

return 0;
}

static void edge_disconnect(struct usb_serial *serial)
{
struct edgeport_serial *edge_serial = usb_get_serial_data(serial);

cancel_delayed_work_sync(&edge_serial->heartbeat_work);
}

static void edge_release(struct usb_serial *serial)
Expand Down
11 changes: 11 additions & 0 deletions drivers/usb/serial/iuu_phoenix.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ struct iuu_private {
u32 clk;
};

static int iuu_attach(struct usb_serial *serial)
{
unsigned char num_ports = serial->num_ports;

if (serial->num_bulk_in < num_ports || serial->num_bulk_out < num_ports)
return -ENODEV;

return 0;
}

static int iuu_port_probe(struct usb_serial_port *port)
{
struct iuu_private *priv;
Expand Down Expand Up @@ -1196,6 +1206,7 @@ static struct usb_serial_driver iuu_device = {
.tiocmset = iuu_tiocmset,
.set_termios = iuu_set_termios,
.init_termios = iuu_init_termios,
.attach = iuu_attach,
.port_probe = iuu_port_probe,
.port_remove = iuu_port_remove,
};
Expand Down
14 changes: 14 additions & 0 deletions drivers/usb/serial/keyspan_pda.c
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,19 @@ MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw");
MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw");
#endif

static int keyspan_pda_attach(struct usb_serial *serial)
{
unsigned char num_ports = serial->num_ports;

if (serial->num_bulk_out < num_ports ||
serial->num_interrupt_in < num_ports) {
dev_err(&serial->interface->dev, "missing endpoints\n");
return -ENODEV;
}

return 0;
}

static int keyspan_pda_port_probe(struct usb_serial_port *port)
{

Expand Down Expand Up @@ -776,6 +789,7 @@ static struct usb_serial_driver keyspan_pda_device = {
.break_ctl = keyspan_pda_break_ctl,
.tiocmget = keyspan_pda_tiocmget,
.tiocmset = keyspan_pda_tiocmset,
.attach = keyspan_pda_attach,
.port_probe = keyspan_pda_port_probe,
.port_remove = keyspan_pda_port_remove,
};
Expand Down
12 changes: 12 additions & 0 deletions drivers/usb/serial/kobil_sct.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@


/* Function prototypes */
static int kobil_attach(struct usb_serial *serial);
static int kobil_port_probe(struct usb_serial_port *probe);
static int kobil_port_remove(struct usb_serial_port *probe);
static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port);
Expand Down Expand Up @@ -86,6 +87,7 @@ static struct usb_serial_driver kobil_device = {
.description = "KOBIL USB smart card terminal",
.id_table = id_table,
.num_ports = 1,
.attach = kobil_attach,
.port_probe = kobil_port_probe,
.port_remove = kobil_port_remove,
.ioctl = kobil_ioctl,
Expand Down Expand Up @@ -113,6 +115,16 @@ struct kobil_private {
};


static int kobil_attach(struct usb_serial *serial)
{
if (serial->num_interrupt_out < serial->num_ports) {
dev_err(&serial->interface->dev, "missing interrupt-out endpoint\n");
return -ENODEV;
}

return 0;
}

static int kobil_port_probe(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
Expand Down
56 changes: 21 additions & 35 deletions drivers/usb/serial/mos7720.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ struct moschip_port {
struct urb *write_urb_pool[NUM_URBS];
};

static struct usb_serial_driver moschip7720_2port_driver;

#define USB_VENDOR_ID_MOSCHIP 0x9710
#define MOSCHIP_DEVICE_ID_7720 0x7720
#define MOSCHIP_DEVICE_ID_7715 0x7715
Expand Down Expand Up @@ -970,25 +968,6 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
tty_port_tty_wakeup(&mos7720_port->port->port);
}

/*
* mos77xx_probe
* this function installs the appropriate read interrupt endpoint callback
* depending on whether the device is a 7720 or 7715, thus avoiding costly
* run-time checks in the high-frequency callback routine itself.
*/
static int mos77xx_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
if (id->idProduct == MOSCHIP_DEVICE_ID_7715)
moschip7720_2port_driver.read_int_callback =
mos7715_interrupt_callback;
else
moschip7720_2port_driver.read_int_callback =
mos7720_interrupt_callback;

return 0;
}

static int mos77xx_calc_num_ports(struct usb_serial *serial)
{
u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
Expand Down Expand Up @@ -1917,6 +1896,11 @@ static int mos7720_startup(struct usb_serial *serial)
u16 product;
int ret_val;

if (serial->num_bulk_in < 2 || serial->num_bulk_out < 2) {
dev_err(&serial->interface->dev, "missing bulk endpoints\n");
return -ENODEV;
}

product = le16_to_cpu(serial->dev->descriptor.idProduct);
dev = serial->dev;

Expand All @@ -1941,26 +1925,32 @@ static int mos7720_startup(struct usb_serial *serial)
tmp->interrupt_in_endpointAddress;
serial->port[1]->interrupt_in_urb = NULL;
serial->port[1]->interrupt_in_buffer = NULL;

if (serial->port[0]->interrupt_in_urb) {
struct urb *urb = serial->port[0]->interrupt_in_urb;

urb->complete = mos7715_interrupt_callback;
}
}

/* setting configuration feature to one */
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
(__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000);

/* start the interrupt urb */
ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL);
if (ret_val)
dev_err(&dev->dev,
"%s - Error %d submitting control urb\n",
__func__, ret_val);

#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
if (product == MOSCHIP_DEVICE_ID_7715) {
ret_val = mos7715_parport_init(serial);
if (ret_val < 0)
return ret_val;
}
#endif
/* start the interrupt urb */
ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL);
if (ret_val) {
dev_err(&dev->dev, "failed to submit interrupt urb: %d\n",
ret_val);
}

/* LSR For Port 1 */
read_mos_reg(serial, 0, MOS7720_LSR, &data);
dev_dbg(&dev->dev, "LSR:%x\n", data);
Expand All @@ -1970,6 +1960,8 @@ static int mos7720_startup(struct usb_serial *serial)

static void mos7720_release(struct usb_serial *serial)
{
usb_kill_urb(serial->port[0]->interrupt_in_urb);

#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
/* close the parallel port */

Expand Down Expand Up @@ -2019,11 +2011,6 @@ static int mos7720_port_probe(struct usb_serial_port *port)
if (!mos7720_port)
return -ENOMEM;

/* Initialize all port interrupt end point to port 0 int endpoint.
* Our device has only one interrupt endpoint common to all ports.
*/
port->interrupt_in_endpointAddress =
port->serial->port[0]->interrupt_in_endpointAddress;
mos7720_port->port = port;

usb_set_serial_port_data(port, mos7720_port);
Expand Down Expand Up @@ -2053,7 +2040,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.close = mos7720_close,
.throttle = mos7720_throttle,
.unthrottle = mos7720_unthrottle,
.probe = mos77xx_probe,
.attach = mos7720_startup,
.release = mos7720_release,
.port_probe = mos7720_port_probe,
Expand All @@ -2067,7 +2053,7 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.chars_in_buffer = mos7720_chars_in_buffer,
.break_ctl = mos7720_break,
.read_bulk_callback = mos7720_bulk_in_callback,
.read_int_callback = NULL /* dynamically assigned in probe() */
.read_int_callback = mos7720_interrupt_callback,
};

static struct usb_serial_driver * const serial_drivers[] = {
Expand Down
Loading

0 comments on commit c8d204b

Please sign in to comment.