Commit eb8878a8 authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman

USB: serial: use port endpoint size to determine if ep is available

It is possible to have a multi-port device with a port lacking an in or
out bulk endpoint. Only checking for num_bulk_in or num_bulk_out is thus not
sufficient to determine whether a specific port has an in or out bulk
endpoint.

This fixes potential null pointer dereferences in the generic open and
write routines, as well as access to uninitialised fifo in write_room
and chars_in_buffer.

Also let write fail with ENODEV (instead of 0) on missing out endpoint
(also on zero-length writes).
Signed-off-by: default avatarJohan Hovold <jhovold@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 63136202
...@@ -130,7 +130,7 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port ...@@ -130,7 +130,7 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
/* if we have a bulk endpoint, start reading from it */ /* if we have a bulk endpoint, start reading from it */
if (serial->num_bulk_in) { if (port->bulk_in_size) {
/* Start reading from the device */ /* Start reading from the device */
usb_fill_bulk_urb(port->read_urb, serial->dev, usb_fill_bulk_urb(port->read_urb, serial->dev,
usb_rcvbulkpipe(serial->dev, usb_rcvbulkpipe(serial->dev,
...@@ -159,10 +159,10 @@ static void generic_cleanup(struct usb_serial_port *port) ...@@ -159,10 +159,10 @@ static void generic_cleanup(struct usb_serial_port *port)
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
if (serial->dev) { if (serial->dev) {
/* shutdown any bulk reads that might be going on */ /* shutdown any bulk transfers that might be going on */
if (serial->num_bulk_out) if (port->bulk_out_size)
usb_kill_urb(port->write_urb); usb_kill_urb(port->write_urb);
if (serial->num_bulk_in) if (port->bulk_in_size)
usb_kill_urb(port->read_urb); usb_kill_urb(port->read_urb);
} }
} }
...@@ -333,15 +333,15 @@ int usb_serial_generic_write(struct tty_struct *tty, ...@@ -333,15 +333,15 @@ int usb_serial_generic_write(struct tty_struct *tty,
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
/* only do something if we have a bulk out endpoint */
if (!port->bulk_out_size)
return -ENODEV;
if (count == 0) { if (count == 0) {
dbg("%s - write request of 0 bytes", __func__); dbg("%s - write request of 0 bytes", __func__);
return 0; return 0;
} }
/* only do something if we have a bulk out endpoint */
if (!serial->num_bulk_out)
return 0;
if (serial->type->max_in_flight_urbs) if (serial->type->max_in_flight_urbs)
return usb_serial_multi_urb_write(tty, port, return usb_serial_multi_urb_write(tty, port,
buf, count); buf, count);
...@@ -364,14 +364,19 @@ int usb_serial_generic_write_room(struct tty_struct *tty) ...@@ -364,14 +364,19 @@ int usb_serial_generic_write_room(struct tty_struct *tty)
int room = 0; int room = 0;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
if (!port->bulk_out_size)
return 0;
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
if (serial->type->max_in_flight_urbs) { if (serial->type->max_in_flight_urbs) {
if (port->urbs_in_flight < serial->type->max_in_flight_urbs) if (port->urbs_in_flight < serial->type->max_in_flight_urbs)
room = port->bulk_out_size * room = port->bulk_out_size *
(serial->type->max_in_flight_urbs - (serial->type->max_in_flight_urbs -
port->urbs_in_flight); port->urbs_in_flight);
} else if (serial->num_bulk_out) } else {
room = kfifo_avail(&port->write_fifo); room = kfifo_avail(&port->write_fifo);
}
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
dbg("%s - returns %d", __func__, room); dbg("%s - returns %d", __func__, room);
...@@ -382,15 +387,18 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) ...@@ -382,15 +387,18 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;
int chars = 0;
unsigned long flags; unsigned long flags;
int chars;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
if (!port->bulk_out_size)
return 0;
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
if (serial->type->max_in_flight_urbs) if (serial->type->max_in_flight_urbs)
chars = port->tx_bytes_flight; chars = port->tx_bytes_flight;
else if (serial->num_bulk_out) else
chars = kfifo_len(&port->write_fifo); chars = kfifo_len(&port->write_fifo);
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment