From: Greg Kroah-Hartman Date: Wed, 24 Oct 2012 17:47:16 +0000 (-0700) Subject: 3.6-stable patches X-Git-Tag: v3.0.49~40 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9a41aea760670697b826fa88fd747a3584875383;p=thirdparty%2Fkernel%2Fstable-queue.git 3.6-stable patches added patches: usb-cp210x-fix-port-data-memory-leak.patch usb-kl5kusb105-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 --- diff --git a/queue-3.6/series b/queue-3.6/series index b489a547e1b..711508b8b62 100644 --- a/queue-3.6/series +++ b/queue-3.6/series @@ -34,3 +34,7 @@ usb-pl2303-fix-port-data-memory-leak.patch 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 diff --git a/queue-3.6/usb-cp210x-fix-port-data-memory-leak.patch b/queue-3.6/usb-cp210x-fix-port-data-memory-leak.patch new file mode 100644 index 00000000000..4abe301fb66 --- /dev/null +++ b/queue-3.6/usb-cp210x-fix-port-data-memory-leak.patch @@ -0,0 +1,131 @@ +From 4295fe7791a1b20c90cbaaa6f23f2fb94218b8a7 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 15 Oct 2012 15:47:20 +0200 +Subject: USB: cp210x: fix port-data memory leak + +From: Johan Hovold + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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); diff --git a/queue-3.6/usb-kl5kusb105-fix-port-data-memory-leak.patch b/queue-3.6/usb-kl5kusb105-fix-port-data-memory-leak.patch new file mode 100644 index 00000000000..6807b6fc246 --- /dev/null +++ b/queue-3.6/usb-kl5kusb105-fix-port-data-memory-leak.patch @@ -0,0 +1,131 @@ +From 99a6f73c495c420df826e5b267fb073fd6766fc3 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 17 Oct 2012 13:35:01 +0200 +Subject: USB: kl5kusb105: fix port-data memory leak + +From: Johan Hovold + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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) diff --git a/queue-3.6/usb-spcp8x5-fix-port-data-memory-leak.patch b/queue-3.6/usb-spcp8x5-fix-port-data-memory-leak.patch new file mode 100644 index 00000000000..ceadf0ea7a6 --- /dev/null +++ b/queue-3.6/usb-spcp8x5-fix-port-data-memory-leak.patch @@ -0,0 +1,104 @@ +From bf90ff5f3b8f67e5b42df4ea4fd543f8010a2676 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 17 Oct 2012 16:31:33 +0200 +Subject: USB: spcp8x5: fix port-data memory leak + +From: Johan Hovold + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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, + }; + diff --git a/queue-3.6/usb-ti_usb_3410_5052-fix-port-data-memory-leak.patch b/queue-3.6/usb-ti_usb_3410_5052-fix-port-data-memory-leak.patch new file mode 100644 index 00000000000..6e64e7fcc85 --- /dev/null +++ b/queue-3.6/usb-ti_usb_3410_5052-fix-port-data-memory-leak.patch @@ -0,0 +1,168 @@ +From 51ef847df74632e7cfdf952afc3887de105b8b35 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 17 Oct 2012 16:31:35 +0200 +Subject: USB: ti_usb_3410_5052: fix port-data memory leak + +From: Johan Hovold + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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) + {