usb-ssu100-fix-port-data-memory-leak.patch
usb-kobil_sct-fix-port-data-memory-leak.patch
usb-cypress_m8-fix-port-data-memory-leak.patch
+usb-cp210x-fix-port-data-memory-leak.patch
+usb-spcp8x5-fix-port-data-memory-leak.patch
+usb-ti_usb_3410_5052-fix-port-data-memory-leak.patch
+usb-kl5kusb105-fix-port-data-memory-leak.patch
--- /dev/null
+From 4295fe7791a1b20c90cbaaa6f23f2fb94218b8a7 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 15 Oct 2012 15:47:20 +0200
+Subject: USB: cp210x: fix port-data memory leak
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 4295fe7791a1b20c90cbaaa6f23f2fb94218b8a7 upstream.
+
+Fix port data memory leak by replacing port private data with serial
+private data.
+
+Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no
+driver is bound) the port private data is no longer freed at
+release.
+
+The private data is used to store the control interface number, but as
+this is the same for all ports on an interface it should be stored as
+usb-serial data anyway.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/cp210x.c | 43 ++++++++++++++++++-------------------------
+ 1 file changed, 18 insertions(+), 25 deletions(-)
+
+--- a/drivers/usb/serial/cp210x.c
++++ b/drivers/usb/serial/cp210x.c
+@@ -164,7 +164,7 @@ static const struct usb_device_id id_tab
+
+ MODULE_DEVICE_TABLE(usb, id_table);
+
+-struct cp210x_port_private {
++struct cp210x_serial_private {
+ __u8 bInterfaceNumber;
+ };
+
+@@ -278,7 +278,7 @@ static int cp210x_get_config(struct usb_
+ unsigned int *data, int size)
+ {
+ struct usb_serial *serial = port->serial;
+- struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
++ struct cp210x_serial_private *spriv = usb_get_serial_data(serial);
+ __le32 *buf;
+ int result, i, length;
+
+@@ -294,7 +294,7 @@ static int cp210x_get_config(struct usb_
+ /* Issue the request, attempting to read 'size' bytes */
+ result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ request, REQTYPE_INTERFACE_TO_HOST, 0x0000,
+- port_priv->bInterfaceNumber, buf, size,
++ spriv->bInterfaceNumber, buf, size,
+ USB_CTRL_GET_TIMEOUT);
+
+ /* Convert data into an array of integers */
+@@ -326,7 +326,7 @@ static int cp210x_set_config(struct usb_
+ unsigned int *data, int size)
+ {
+ struct usb_serial *serial = port->serial;
+- struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
++ struct cp210x_serial_private *spriv = usb_get_serial_data(serial);
+ __le32 *buf;
+ int result, i, length;
+
+@@ -348,13 +348,13 @@ static int cp210x_set_config(struct usb_
+ result = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ request, REQTYPE_HOST_TO_INTERFACE, 0x0000,
+- port_priv->bInterfaceNumber, buf, size,
++ spriv->bInterfaceNumber, buf, size,
+ USB_CTRL_SET_TIMEOUT);
+ } else {
+ result = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ request, REQTYPE_HOST_TO_INTERFACE, data[0],
+- port_priv->bInterfaceNumber, NULL, 0,
++ spriv->bInterfaceNumber, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ }
+
+@@ -854,37 +854,30 @@ static void cp210x_break_ctl (struct tty
+
+ static int cp210x_startup(struct usb_serial *serial)
+ {
+- struct cp210x_port_private *port_priv;
+- int i;
++ struct usb_host_interface *cur_altsetting;
++ struct cp210x_serial_private *spriv;
+
+ /* cp210x buffers behave strangely unless device is reset */
+ usb_reset_device(serial->dev);
+
+- for (i = 0; i < serial->num_ports; i++) {
+- port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
+- if (!port_priv)
+- return -ENOMEM;
+-
+- memset(port_priv, 0x00, sizeof(*port_priv));
+- port_priv->bInterfaceNumber =
+- serial->interface->cur_altsetting->desc.bInterfaceNumber;
++ spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
++ if (!spriv)
++ return -ENOMEM;
+
+- usb_set_serial_port_data(serial->port[i], port_priv);
+- }
++ cur_altsetting = serial->interface->cur_altsetting;
++ spriv->bInterfaceNumber = cur_altsetting->desc.bInterfaceNumber;
++
++ usb_set_serial_data(serial, spriv);
+
+ return 0;
+ }
+
+ static void cp210x_release(struct usb_serial *serial)
+ {
+- struct cp210x_port_private *port_priv;
+- int i;
++ struct cp210x_serial_private *spriv;
+
+- for (i = 0; i < serial->num_ports; i++) {
+- port_priv = usb_get_serial_port_data(serial->port[i]);
+- kfree(port_priv);
+- usb_set_serial_port_data(serial->port[i], NULL);
+- }
++ spriv = usb_get_serial_data(serial);
++ kfree(spriv);
+ }
+
+ module_usb_serial_driver(serial_drivers, id_table);
--- /dev/null
+From 99a6f73c495c420df826e5b267fb073fd6766fc3 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 17 Oct 2012 13:35:01 +0200
+Subject: USB: kl5kusb105: fix port-data memory leak
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 99a6f73c495c420df826e5b267fb073fd6766fc3 upstream.
+
+Fix port-data memory leak by replacing attach and release with
+port_probe and port_remove.
+
+Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no
+driver is bound) the port private data is no longer freed at release as
+it is no longer accessible.
+
+Note that the write waitqueue was initialised but never used.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/kl5kusb105.c | 68 ++++++++++++++--------------------------
+ 1 file changed, 25 insertions(+), 43 deletions(-)
+
+--- a/drivers/usb/serial/kl5kusb105.c
++++ b/drivers/usb/serial/kl5kusb105.c
+@@ -62,8 +62,8 @@ static bool debug;
+ /*
+ * Function prototypes
+ */
+-static int klsi_105_startup(struct usb_serial *serial);
+-static void klsi_105_release(struct usb_serial *serial);
++static int klsi_105_port_probe(struct usb_serial_port *port);
++static int klsi_105_port_remove(struct usb_serial_port *port);
+ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port);
+ static void klsi_105_close(struct usb_serial_port *port);
+ static void klsi_105_set_termios(struct tty_struct *tty,
+@@ -101,8 +101,8 @@ static struct usb_serial_driver kl5kusb1
+ /*.break_ctl = klsi_105_break_ctl,*/
+ .tiocmget = klsi_105_tiocmget,
+ .tiocmset = klsi_105_tiocmset,
+- .attach = klsi_105_startup,
+- .release = klsi_105_release,
++ .port_probe = klsi_105_port_probe,
++ .port_remove = klsi_105_port_remove,
+ .throttle = usb_serial_generic_throttle,
+ .unthrottle = usb_serial_generic_unthrottle,
+ .process_read_urb = klsi_105_process_read_urb,
+@@ -225,58 +225,40 @@ static int klsi_105_get_line_state(struc
+ * Driver's tty interface functions
+ */
+
+-static int klsi_105_startup(struct usb_serial *serial)
++static int klsi_105_port_probe(struct usb_serial_port *port)
+ {
+ struct klsi_105_private *priv;
+- int i;
+
+- /* check if we support the product id (see keyspan.c)
+- * FIXME
+- */
+-
+- /* allocate the private data structure */
+- for (i = 0; i < serial->num_ports; i++) {
+- priv = kmalloc(sizeof(struct klsi_105_private),
+- GFP_KERNEL);
+- if (!priv) {
+- dbg("%skmalloc for klsi_105_private failed.", __func__);
+- i--;
+- goto err_cleanup;
+- }
+- /* set initial values for control structures */
+- priv->cfg.pktlen = 5;
+- priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+- priv->cfg.databits = kl5kusb105a_dtb_8;
+- priv->cfg.unknown1 = 0;
+- priv->cfg.unknown2 = 1;
++ priv = kmalloc(sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
+
+- priv->line_state = 0;
++ /* set initial values for control structures */
++ priv->cfg.pktlen = 5;
++ priv->cfg.baudrate = kl5kusb105a_sio_b9600;
++ priv->cfg.databits = kl5kusb105a_dtb_8;
++ priv->cfg.unknown1 = 0;
++ priv->cfg.unknown2 = 1;
+
+- usb_set_serial_port_data(serial->port[i], priv);
++ priv->line_state = 0;
+
+- spin_lock_init(&priv->lock);
++ spin_lock_init(&priv->lock);
+
+- /* priv->termios is left uninitialized until port opening */
+- init_waitqueue_head(&serial->port[i]->write_wait);
+- }
++ /* priv->termios is left uninitialized until port opening */
+
+- return 0;
++ usb_set_serial_port_data(port, priv);
+
+-err_cleanup:
+- for (; i >= 0; i--) {
+- priv = usb_get_serial_port_data(serial->port[i]);
+- kfree(priv);
+- usb_set_serial_port_data(serial->port[i], NULL);
+- }
+- return -ENOMEM;
++ return 0;
+ }
+
+-static void klsi_105_release(struct usb_serial *serial)
++static int klsi_105_port_remove(struct usb_serial_port *port)
+ {
+- int i;
++ struct klsi_105_private *priv;
+
+- for (i = 0; i < serial->num_ports; ++i)
+- kfree(usb_get_serial_port_data(serial->port[i]));
++ priv = usb_get_serial_port_data(port);
++ kfree(priv);
++
++ return 0;
+ }
+
+ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
--- /dev/null
+From bf90ff5f3b8f67e5b42df4ea4fd543f8010a2676 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 17 Oct 2012 16:31:33 +0200
+Subject: USB: spcp8x5: fix port-data memory leak
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit bf90ff5f3b8f67e5b42df4ea4fd543f8010a2676 upstream.
+
+Fix port-data memory leak by replacing attach and release with
+port_probe and port_remove.
+
+Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no
+driver is bound) the port private data is no longer freed at release as
+it is no longer accessible.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/spcp8x5.c | 48 +++++++++++++++++--------------------------
+ 1 file changed, 19 insertions(+), 29 deletions(-)
+
+--- a/drivers/usb/serial/spcp8x5.c
++++ b/drivers/usb/serial/spcp8x5.c
+@@ -159,13 +159,10 @@ struct spcp8x5_private {
+ u8 line_status;
+ };
+
+-/* desc : when device plug in,this function would be called.
+- * thanks to usb_serial subsystem,then do almost every things for us. And what
+- * we should do just alloc the buffer */
+-static int spcp8x5_startup(struct usb_serial *serial)
++static int spcp8x5_port_probe(struct usb_serial_port *port)
+ {
++ struct usb_serial *serial = port->serial;
+ struct spcp8x5_private *priv;
+- int i;
+ enum spcp8x5_type type = SPCP825_007_TYPE;
+ u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
+
+@@ -182,34 +179,27 @@ static int spcp8x5_startup(struct usb_se
+ type = SPCP825_PHILIP_TYPE;
+ dev_dbg(&serial->dev->dev, "device type = %d\n", (int)type);
+
+- for (i = 0; i < serial->num_ports; ++i) {
+- priv = kzalloc(sizeof(struct spcp8x5_private), GFP_KERNEL);
+- if (!priv)
+- goto cleanup;
+-
+- spin_lock_init(&priv->lock);
+- init_waitqueue_head(&priv->delta_msr_wait);
+- priv->type = type;
+- usb_set_serial_port_data(serial->port[i] , priv);
+- }
++ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ spin_lock_init(&priv->lock);
++ init_waitqueue_head(&priv->delta_msr_wait);
++ priv->type = type;
++
++ usb_set_serial_port_data(port , priv);
+
+ return 0;
+-cleanup:
+- for (--i; i >= 0; --i) {
+- priv = usb_get_serial_port_data(serial->port[i]);
+- kfree(priv);
+- usb_set_serial_port_data(serial->port[i] , NULL);
+- }
+- return -ENOMEM;
+ }
+
+-/* call when the device plug out. free all the memory alloced by probe */
+-static void spcp8x5_release(struct usb_serial *serial)
++static int spcp8x5_port_remove(struct usb_serial_port *port)
+ {
+- int i;
++ struct spcp8x5_private *priv;
+
+- for (i = 0; i < serial->num_ports; i++)
+- kfree(usb_get_serial_port_data(serial->port[i]));
++ priv = usb_get_serial_port_data(port);
++ kfree(priv);
++
++ return 0;
+ }
+
+ /* set the modem control line of the device.
+@@ -651,8 +641,8 @@ static struct usb_serial_driver spcp8x5_
+ .ioctl = spcp8x5_ioctl,
+ .tiocmget = spcp8x5_tiocmget,
+ .tiocmset = spcp8x5_tiocmset,
+- .attach = spcp8x5_startup,
+- .release = spcp8x5_release,
++ .port_probe = spcp8x5_port_probe,
++ .port_remove = spcp8x5_port_remove,
+ .process_read_urb = spcp8x5_process_read_urb,
+ };
+
--- /dev/null
+From 51ef847df74632e7cfdf952afc3887de105b8b35 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 17 Oct 2012 16:31:35 +0200
+Subject: USB: ti_usb_3410_5052: fix port-data memory leak
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 51ef847df74632e7cfdf952afc3887de105b8b35 upstream.
+
+Fix port-data memory leak by moving port data allocation and
+deallocation to port_probe and port_remove.
+
+Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no
+driver is bound) the port private data is no longer freed at release as
+it is no longer accessible.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/ti_usb_3410_5052.c | 88 ++++++++++++++++------------------
+ 1 file changed, 43 insertions(+), 45 deletions(-)
+
+--- a/drivers/usb/serial/ti_usb_3410_5052.c
++++ b/drivers/usb/serial/ti_usb_3410_5052.c
+@@ -98,6 +98,8 @@ struct ti_device {
+
+ static int ti_startup(struct usb_serial *serial);
+ static void ti_release(struct usb_serial *serial);
++static int ti_port_probe(struct usb_serial_port *port);
++static int ti_port_remove(struct usb_serial_port *port);
+ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port);
+ static void ti_close(struct usb_serial_port *port);
+ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
+@@ -223,6 +225,8 @@ static struct usb_serial_driver ti_1port
+ .num_ports = 1,
+ .attach = ti_startup,
+ .release = ti_release,
++ .port_probe = ti_port_probe,
++ .port_remove = ti_port_remove,
+ .open = ti_open,
+ .close = ti_close,
+ .write = ti_write,
+@@ -251,6 +255,8 @@ static struct usb_serial_driver ti_2port
+ .num_ports = 2,
+ .attach = ti_startup,
+ .release = ti_release,
++ .port_probe = ti_port_probe,
++ .port_remove = ti_port_remove,
+ .open = ti_open,
+ .close = ti_close,
+ .write = ti_write,
+@@ -358,11 +364,8 @@ module_exit(ti_exit);
+ static int ti_startup(struct usb_serial *serial)
+ {
+ struct ti_device *tdev;
+- struct ti_port *tport;
+ struct usb_device *dev = serial->dev;
+ int status;
+- int i;
+-
+
+ dbg("%s - product 0x%4X, num configurations %d, configuration value %d",
+ __func__, le16_to_cpu(dev->descriptor.idProduct),
+@@ -409,42 +412,8 @@ static int ti_startup(struct usb_serial
+ goto free_tdev;
+ }
+
+- /* set up port structures */
+- for (i = 0; i < serial->num_ports; ++i) {
+- tport = kzalloc(sizeof(struct ti_port), GFP_KERNEL);
+- if (tport == NULL) {
+- dev_err(&dev->dev, "%s - out of memory\n", __func__);
+- status = -ENOMEM;
+- goto free_tports;
+- }
+- spin_lock_init(&tport->tp_lock);
+- tport->tp_uart_base_addr = (i == 0 ?
+- TI_UART1_BASE_ADDR : TI_UART2_BASE_ADDR);
+- tport->tp_closing_wait = closing_wait;
+- init_waitqueue_head(&tport->tp_msr_wait);
+- init_waitqueue_head(&tport->tp_write_wait);
+- if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE,
+- GFP_KERNEL)) {
+- dev_err(&dev->dev, "%s - out of memory\n", __func__);
+- kfree(tport);
+- status = -ENOMEM;
+- goto free_tports;
+- }
+- tport->tp_port = serial->port[i];
+- tport->tp_tdev = tdev;
+- usb_set_serial_port_data(serial->port[i], tport);
+- tport->tp_uart_mode = 0; /* default is RS232 */
+- }
+-
+ return 0;
+
+-free_tports:
+- for (--i; i >= 0; --i) {
+- tport = usb_get_serial_port_data(serial->port[i]);
+- kfifo_free(&tport->write_fifo);
+- kfree(tport);
+- usb_set_serial_port_data(serial->port[i], NULL);
+- }
+ free_tdev:
+ kfree(tdev);
+ usb_set_serial_data(serial, NULL);
+@@ -454,21 +423,50 @@ free_tdev:
+
+ static void ti_release(struct usb_serial *serial)
+ {
+- int i;
+ struct ti_device *tdev = usb_get_serial_data(serial);
++
++ kfree(tdev);
++}
++
++static int ti_port_probe(struct usb_serial_port *port)
++{
+ struct ti_port *tport;
+
+- for (i = 0; i < serial->num_ports; ++i) {
+- tport = usb_get_serial_port_data(serial->port[i]);
+- if (tport) {
+- kfifo_free(&tport->write_fifo);
+- kfree(tport);
+- }
++ tport = kzalloc(sizeof(*tport), GFP_KERNEL);
++ if (!tport)
++ return -ENOMEM;
++
++ spin_lock_init(&tport->tp_lock);
++ if (port == port->serial->port[0])
++ tport->tp_uart_base_addr = TI_UART1_BASE_ADDR;
++ else
++ tport->tp_uart_base_addr = TI_UART2_BASE_ADDR;
++ tport->tp_closing_wait = closing_wait;
++ init_waitqueue_head(&tport->tp_msr_wait);
++ init_waitqueue_head(&tport->tp_write_wait);
++ if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, GFP_KERNEL)) {
++ kfree(tport);
++ return -ENOMEM;
+ }
++ tport->tp_port = port;
++ tport->tp_tdev = usb_get_serial_data(port->serial);
++ tport->tp_uart_mode = 0; /* default is RS232 */
+
+- kfree(tdev);
++ usb_set_serial_port_data(port, tport);
++
++ return 0;
+ }
+
++static int ti_port_remove(struct usb_serial_port *port)
++{
++ struct ti_port *tport;
++
++ tport = usb_get_serial_port_data(port);
++ kfifo_free(&tport->write_fifo);
++ kfree(tport);
++
++ return 0;
++}
+
+ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
+ {