From: Greg Kroah-Hartman Date: Wed, 24 Oct 2012 17:40:25 +0000 (-0700) Subject: 3.6-stable patches X-Git-Tag: v3.0.49~41 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e0985872fa20ee4d85f0b22a23715777b11de945;p=thirdparty%2Fkernel%2Fstable-queue.git 3.6-stable patches added patches: usb-ark3116-fix-null-pointer-dereference.patch usb-belkin_sa-fix-port-data-memory-leak.patch usb-cypress_m8-fix-port-data-memory-leak.patch usb-f81232-fix-port-data-memory-leak.patch usb-kobil_sct-fix-port-data-memory-leak.patch usb-oti6858-fix-port-data-memory-leak.patch usb-pl2303-fix-port-data-memory-leak.patch usb-ssu100-fix-port-data-memory-leak.patch --- diff --git a/queue-3.6/series b/queue-3.6/series index 078db074642..b489a547e1b 100644 --- a/queue-3.6/series +++ b/queue-3.6/series @@ -26,3 +26,11 @@ usb-musb-am35xx-drop-spurious-unplugging-a-device.patch usb-host-xhci-new-system-added-for-compliance-mode-patch-on-sn65lvpe502cp.patch usb-iuu_phoenix-fix-port-data-memory-leak.patch usb-iuu_phoenix-fix-sysfs-attribute-creation.patch +usb-ark3116-fix-null-pointer-dereference.patch +usb-f81232-fix-port-data-memory-leak.patch +usb-oti6858-fix-port-data-memory-leak.patch +usb-belkin_sa-fix-port-data-memory-leak.patch +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 diff --git a/queue-3.6/usb-ark3116-fix-null-pointer-dereference.patch b/queue-3.6/usb-ark3116-fix-null-pointer-dereference.patch new file mode 100644 index 00000000000..65e1790f646 --- /dev/null +++ b/queue-3.6/usb-ark3116-fix-null-pointer-dereference.patch @@ -0,0 +1,86 @@ +From 7bdce71822f471433dd3014692e9096996c7b5f0 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 15 Oct 2012 18:20:52 +0200 +Subject: USB: ark3116: fix NULL-pointer dereference + +From: Johan Hovold + +commit 7bdce71822f471433dd3014692e9096996c7b5f0 upstream. + +Fix NULL-pointer dereference at release 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 NULL when release is called. + +Compile-only tested. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/ark3116.c | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +--- a/drivers/usb/serial/ark3116.c ++++ b/drivers/usb/serial/ark3116.c +@@ -126,9 +126,6 @@ static inline int calc_divisor(int bps) + + static int ark3116_attach(struct usb_serial *serial) + { +- struct usb_serial_port *port = serial->port[0]; +- struct ark3116_private *priv; +- + /* make sure we have our end-points */ + if ((serial->num_bulk_in == 0) || + (serial->num_bulk_out == 0) || +@@ -143,8 +140,15 @@ static int ark3116_attach(struct usb_ser + return -EINVAL; + } + +- priv = kzalloc(sizeof(struct ark3116_private), +- GFP_KERNEL); ++ return 0; ++} ++ ++static int ark3116_port_probe(struct usb_serial_port *port) ++{ ++ struct usb_serial *serial = port->serial; ++ struct ark3116_private *priv; ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + +@@ -199,18 +203,15 @@ static int ark3116_attach(struct usb_ser + return 0; + } + +-static void ark3116_release(struct usb_serial *serial) ++static int ark3116_port_remove(struct usb_serial_port *port) + { +- struct usb_serial_port *port = serial->port[0]; + struct ark3116_private *priv = usb_get_serial_port_data(port); + + /* device is closed, so URBs and DMA should be down */ +- +- usb_set_serial_port_data(port, NULL); +- + mutex_destroy(&priv->hw_lock); +- + kfree(priv); ++ ++ return 0; + } + + static void ark3116_init_termios(struct tty_struct *tty) +@@ -725,7 +726,8 @@ static struct usb_serial_driver ark3116_ + .id_table = id_table, + .num_ports = 1, + .attach = ark3116_attach, +- .release = ark3116_release, ++ .port_probe = ark3116_port_probe, ++ .port_remove = ark3116_port_remove, + .set_termios = ark3116_set_termios, + .init_termios = ark3116_init_termios, + .ioctl = ark3116_ioctl, diff --git a/queue-3.6/usb-belkin_sa-fix-port-data-memory-leak.patch b/queue-3.6/usb-belkin_sa-fix-port-data-memory-leak.patch new file mode 100644 index 00000000000..8fc40631201 --- /dev/null +++ b/queue-3.6/usb-belkin_sa-fix-port-data-memory-leak.patch @@ -0,0 +1,99 @@ +From fa919751a2d26a88140fc5810124dd81644efe51 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 15 Oct 2012 18:20:53 +0200 +Subject: USB: belkin_sa: fix port-data memory leak + +From: Johan Hovold + +commit fa919751a2d26a88140fc5810124dd81644efe51 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/belkin_sa.c | 31 +++++++++++++++---------------- + 1 file changed, 15 insertions(+), 16 deletions(-) + +--- a/drivers/usb/serial/belkin_sa.c ++++ b/drivers/usb/serial/belkin_sa.c +@@ -47,8 +47,8 @@ static bool debug; + #define DRIVER_DESC "USB Belkin Serial converter driver" + + /* function prototypes for a Belkin USB Serial Adapter F5U103 */ +-static int belkin_sa_startup(struct usb_serial *serial); +-static void belkin_sa_release(struct usb_serial *serial); ++static int belkin_sa_port_probe(struct usb_serial_port *port); ++static int belkin_sa_port_remove(struct usb_serial_port *port); + static int belkin_sa_open(struct tty_struct *tty, + struct usb_serial_port *port); + static void belkin_sa_close(struct usb_serial_port *port); +@@ -90,8 +90,8 @@ static struct usb_serial_driver belkin_d + .break_ctl = belkin_sa_break_ctl, + .tiocmget = belkin_sa_tiocmget, + .tiocmset = belkin_sa_tiocmset, +- .attach = belkin_sa_startup, +- .release = belkin_sa_release, ++ .port_probe = belkin_sa_port_probe, ++ .port_remove = belkin_sa_port_remove, + }; + + static struct usb_serial_driver * const serial_drivers[] = { +@@ -120,17 +120,15 @@ struct belkin_sa_private { + (c), BELKIN_SA_SET_REQUEST_TYPE, \ + (v), 0, NULL, 0, WDR_TIMEOUT) + +-/* do some startup allocations not currently performed by usb_serial_probe() */ +-static int belkin_sa_startup(struct usb_serial *serial) ++static int belkin_sa_port_probe(struct usb_serial_port *port) + { +- struct usb_device *dev = serial->dev; ++ struct usb_device *dev = port->serial->dev; + struct belkin_sa_private *priv; + +- /* allocate the private data structure */ + priv = kmalloc(sizeof(struct belkin_sa_private), GFP_KERNEL); + if (!priv) +- return -1; /* error */ +- /* set initial values for control structures */ ++ return -ENOMEM; ++ + spin_lock_init(&priv->lock); + priv->control_state = 0; + priv->last_lsr = 0; +@@ -142,18 +140,19 @@ static int belkin_sa_startup(struct usb_ + le16_to_cpu(dev->descriptor.bcdDevice), + priv->bad_flow_control); + +- init_waitqueue_head(&serial->port[0]->write_wait); +- usb_set_serial_port_data(serial->port[0], priv); ++ usb_set_serial_port_data(port, priv); + + return 0; + } + +-static void belkin_sa_release(struct usb_serial *serial) ++static int belkin_sa_port_remove(struct usb_serial_port *port) + { +- int i; ++ struct belkin_sa_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 belkin_sa_open(struct tty_struct *tty, diff --git a/queue-3.6/usb-cypress_m8-fix-port-data-memory-leak.patch b/queue-3.6/usb-cypress_m8-fix-port-data-memory-leak.patch new file mode 100644 index 00000000000..c19661fd764 --- /dev/null +++ b/queue-3.6/usb-cypress_m8-fix-port-data-memory-leak.patch @@ -0,0 +1,188 @@ +From 5c1a0f418d8d985f3a62849bcac43fc5404cc592 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 17 Oct 2012 13:34:55 +0200 +Subject: USB: cypress_m8: fix port-data memory leak + +From: Johan Hovold + +commit 5c1a0f418d8d985f3a62849bcac43fc5404cc592 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/cypress_m8.c | 82 ++++++++++++++++++++-------------------- + 1 file changed, 41 insertions(+), 41 deletions(-) + +--- a/drivers/usb/serial/cypress_m8.c ++++ b/drivers/usb/serial/cypress_m8.c +@@ -124,10 +124,10 @@ struct cypress_private { + }; + + /* function prototypes for the Cypress USB to serial device */ +-static int cypress_earthmate_startup(struct usb_serial *serial); +-static int cypress_hidcom_startup(struct usb_serial *serial); +-static int cypress_ca42v2_startup(struct usb_serial *serial); +-static void cypress_release(struct usb_serial *serial); ++static int cypress_earthmate_port_probe(struct usb_serial_port *port); ++static int cypress_hidcom_port_probe(struct usb_serial_port *port); ++static int cypress_ca42v2_port_probe(struct usb_serial_port *port); ++static int cypress_port_remove(struct usb_serial_port *port); + static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port); + static void cypress_close(struct usb_serial_port *port); + static void cypress_dtr_rts(struct usb_serial_port *port, int on); +@@ -157,8 +157,8 @@ static struct usb_serial_driver cypress_ + .description = "DeLorme Earthmate USB", + .id_table = id_table_earthmate, + .num_ports = 1, +- .attach = cypress_earthmate_startup, +- .release = cypress_release, ++ .port_probe = cypress_earthmate_port_probe, ++ .port_remove = cypress_port_remove, + .open = cypress_open, + .close = cypress_close, + .dtr_rts = cypress_dtr_rts, +@@ -183,8 +183,8 @@ static struct usb_serial_driver cypress_ + .description = "HID->COM RS232 Adapter", + .id_table = id_table_cyphidcomrs232, + .num_ports = 1, +- .attach = cypress_hidcom_startup, +- .release = cypress_release, ++ .port_probe = cypress_hidcom_port_probe, ++ .port_remove = cypress_port_remove, + .open = cypress_open, + .close = cypress_close, + .dtr_rts = cypress_dtr_rts, +@@ -209,8 +209,8 @@ static struct usb_serial_driver cypress_ + .description = "Nokia CA-42 V2 Adapter", + .id_table = id_table_nokiaca42v2, + .num_ports = 1, +- .attach = cypress_ca42v2_startup, +- .release = cypress_release, ++ .port_probe = cypress_ca42v2_port_probe, ++ .port_remove = cypress_port_remove, + .open = cypress_open, + .close = cypress_close, + .dtr_rts = cypress_dtr_rts, +@@ -437,10 +437,10 @@ static void cypress_set_dead(struct usb_ + *****************************************************************************/ + + +-static int generic_startup(struct usb_serial *serial) ++static int cypress_generic_port_probe(struct usb_serial_port *port) + { ++ struct usb_serial *serial = port->serial; + struct cypress_private *priv; +- struct usb_serial_port *port = serial->port[0]; + + priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL); + if (!priv) +@@ -489,15 +489,17 @@ static int generic_startup(struct usb_se + } + + +-static int cypress_earthmate_startup(struct usb_serial *serial) ++static int cypress_earthmate_port_probe(struct usb_serial_port *port) + { ++ struct usb_serial *serial = port->serial; + struct cypress_private *priv; +- struct usb_serial_port *port = serial->port[0]; ++ int ret; + +- if (generic_startup(serial)) { ++ ret = cypress_generic_port_probe(port); ++ if (ret) { + dbg("%s - Failed setting up port %d", __func__, + port->number); +- return 1; ++ return ret; + } + + priv = usb_get_serial_port_data(port); +@@ -517,54 +519,52 @@ static int cypress_earthmate_startup(str + } + + return 0; +-} /* cypress_earthmate_startup */ +- ++} + +-static int cypress_hidcom_startup(struct usb_serial *serial) ++static int cypress_hidcom_port_probe(struct usb_serial_port *port) + { + struct cypress_private *priv; ++ int ret; + +- if (generic_startup(serial)) { +- dbg("%s - Failed setting up port %d", __func__, +- serial->port[0]->number); +- return 1; ++ ret = cypress_generic_port_probe(port); ++ if (ret) { ++ dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__); ++ return ret; + } + +- priv = usb_get_serial_port_data(serial->port[0]); ++ priv = usb_get_serial_port_data(port); + priv->chiptype = CT_CYPHIDCOM; + + return 0; +-} /* cypress_hidcom_startup */ +- ++} + +-static int cypress_ca42v2_startup(struct usb_serial *serial) ++static int cypress_ca42v2_port_probe(struct usb_serial_port *port) + { + struct cypress_private *priv; ++ int ret; + +- if (generic_startup(serial)) { +- dbg("%s - Failed setting up port %d", __func__, +- serial->port[0]->number); +- return 1; ++ ret = cypress_generic_port_probe(port); ++ if (ret) { ++ dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__); ++ return ret; + } + +- priv = usb_get_serial_port_data(serial->port[0]); ++ priv = usb_get_serial_port_data(port); + priv->chiptype = CT_CA42V2; + + return 0; +-} /* cypress_ca42v2_startup */ +- ++} + +-static void cypress_release(struct usb_serial *serial) ++static int cypress_port_remove(struct usb_serial_port *port) + { + struct cypress_private *priv; + +- /* all open ports are closed at this point */ +- priv = usb_get_serial_port_data(serial->port[0]); ++ priv = usb_get_serial_port_data(port); + +- if (priv) { +- kfifo_free(&priv->write_fifo); +- kfree(priv); +- } ++ kfifo_free(&priv->write_fifo); ++ kfree(priv); ++ ++ return 0; + } + + diff --git a/queue-3.6/usb-f81232-fix-port-data-memory-leak.patch b/queue-3.6/usb-f81232-fix-port-data-memory-leak.patch new file mode 100644 index 00000000000..d451fa30a42 --- /dev/null +++ b/queue-3.6/usb-f81232-fix-port-data-memory-leak.patch @@ -0,0 +1,93 @@ +From 3124d1d71d3df59d40b913b5481df58099e811d1 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 17 Oct 2012 13:34:56 +0200 +Subject: USB: f81232: fix port-data memory leak + +From: Johan Hovold + +commit 3124d1d71d3df59d40b913b5481df58099e811d1 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/f81232.c | 43 +++++++++++++++++-------------------------- + 1 file changed, 17 insertions(+), 26 deletions(-) + +--- a/drivers/usb/serial/f81232.c ++++ b/drivers/usb/serial/f81232.c +@@ -319,39 +319,30 @@ static int f81232_ioctl(struct tty_struc + return -ENOIOCTLCMD; + } + +-static int f81232_startup(struct usb_serial *serial) ++static int f81232_port_probe(struct usb_serial_port *port) + { + struct f81232_private *priv; +- int i; + +- for (i = 0; i < serial->num_ports; ++i) { +- priv = kzalloc(sizeof(struct f81232_private), GFP_KERNEL); +- if (!priv) +- goto cleanup; +- spin_lock_init(&priv->lock); +- init_waitqueue_head(&priv->delta_msr_wait); +- usb_set_serial_port_data(serial->port[i], priv); +- } +- return 0; ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ spin_lock_init(&priv->lock); ++ init_waitqueue_head(&priv->delta_msr_wait); ++ ++ usb_set_serial_port_data(port, priv); + +-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; ++ return 0; + } + +-static void f81232_release(struct usb_serial *serial) ++static int f81232_port_remove(struct usb_serial_port *port) + { +- int i; + struct f81232_private *priv; + +- for (i = 0; i < serial->num_ports; ++i) { +- priv = usb_get_serial_port_data(serial->port[i]); +- kfree(priv); +- } ++ priv = usb_get_serial_port_data(port); ++ kfree(priv); ++ ++ return 0; + } + + static struct usb_serial_driver f81232_device = { +@@ -374,8 +365,8 @@ static struct usb_serial_driver f81232_d + .tiocmset = f81232_tiocmset, + .process_read_urb = f81232_process_read_urb, + .read_int_callback = f81232_read_int_callback, +- .attach = f81232_startup, +- .release = f81232_release, ++ .port_probe = f81232_port_probe, ++ .port_remove = f81232_port_remove, + }; + + static struct usb_serial_driver * const serial_drivers[] = { diff --git a/queue-3.6/usb-kobil_sct-fix-port-data-memory-leak.patch b/queue-3.6/usb-kobil_sct-fix-port-data-memory-leak.patch new file mode 100644 index 00000000000..d130bb4e44d --- /dev/null +++ b/queue-3.6/usb-kobil_sct-fix-port-data-memory-leak.patch @@ -0,0 +1,89 @@ +From 95940a04bfe8a4d246f4ca17c6a3b00148bdead0 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 17 Oct 2012 13:35:02 +0200 +Subject: USB: kobil_sct: fix port-data memory leak + +From: Johan Hovold + +commit 95940a04bfe8a4d246f4ca17c6a3b00148bdead0 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/kobil_sct.c | 23 +++++++++++++---------- + 1 file changed, 13 insertions(+), 10 deletions(-) + +--- a/drivers/usb/serial/kobil_sct.c ++++ b/drivers/usb/serial/kobil_sct.c +@@ -56,8 +56,8 @@ static bool debug; + + + /* Function prototypes */ +-static int kobil_startup(struct usb_serial *serial); +-static void kobil_release(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); + static void kobil_close(struct usb_serial_port *port); + static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, +@@ -91,8 +91,8 @@ static struct usb_serial_driver kobil_de + .description = "KOBIL USB smart card terminal", + .id_table = id_table, + .num_ports = 1, +- .attach = kobil_startup, +- .release = kobil_release, ++ .port_probe = kobil_port_probe, ++ .port_remove = kobil_port_remove, + .ioctl = kobil_ioctl, + .set_termios = kobil_set_termios, + .init_termios = kobil_init_termios, +@@ -119,9 +119,10 @@ struct kobil_private { + }; + + +-static int kobil_startup(struct usb_serial *serial) ++static int kobil_port_probe(struct usb_serial_port *port) + { + int i; ++ struct usb_serial *serial = port->serial; + struct kobil_private *priv; + struct usb_device *pdev; + struct usb_host_config *actconfig; +@@ -152,7 +153,7 @@ static int kobil_startup(struct usb_seri + printk(KERN_DEBUG "KOBIL KAAN SIM detected\n"); + break; + } +- usb_set_serial_port_data(serial->port[0], priv); ++ usb_set_serial_port_data(port, priv); + + /* search for the necessary endpoints */ + pdev = serial->dev; +@@ -180,12 +181,14 @@ static int kobil_startup(struct usb_seri + } + + +-static void kobil_release(struct usb_serial *serial) ++static int kobil_port_remove(struct usb_serial_port *port) + { +- int i; ++ struct kobil_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 void kobil_init_termios(struct tty_struct *tty) diff --git a/queue-3.6/usb-oti6858-fix-port-data-memory-leak.patch b/queue-3.6/usb-oti6858-fix-port-data-memory-leak.patch new file mode 100644 index 00000000000..e5b600c4e7f --- /dev/null +++ b/queue-3.6/usb-oti6858-fix-port-data-memory-leak.patch @@ -0,0 +1,126 @@ +From 289b076f89c2c3260e914dad18ae12f193ea86d5 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 17 Oct 2012 16:31:32 +0200 +Subject: USB: oti6858: fix port-data memory leak + +From: Johan Hovold + +commit 289b076f89c2c3260e914dad18ae12f193ea86d5 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/oti6858.c | 68 +++++++++++++++++-------------------------- + 1 file changed, 28 insertions(+), 40 deletions(-) + +--- a/drivers/usb/serial/oti6858.c ++++ b/drivers/usb/serial/oti6858.c +@@ -139,8 +139,8 @@ static int oti6858_chars_in_buffer(struc + static int oti6858_tiocmget(struct tty_struct *tty); + static int oti6858_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear); +-static int oti6858_startup(struct usb_serial *serial); +-static void oti6858_release(struct usb_serial *serial); ++static int oti6858_port_probe(struct usb_serial_port *port); ++static int oti6858_port_remove(struct usb_serial_port *port); + + /* device info */ + static struct usb_serial_driver oti6858_device = { +@@ -163,8 +163,8 @@ static struct usb_serial_driver oti6858_ + .write_bulk_callback = oti6858_write_bulk_callback, + .write_room = oti6858_write_room, + .chars_in_buffer = oti6858_chars_in_buffer, +- .attach = oti6858_startup, +- .release = oti6858_release, ++ .port_probe = oti6858_port_probe, ++ .port_remove = oti6858_port_remove, + }; + + static struct usb_serial_driver * const serial_drivers[] = { +@@ -333,36 +333,33 @@ static void send_data(struct work_struct + usb_serial_port_softint(port); + } + +-static int oti6858_startup(struct usb_serial *serial) ++static int oti6858_port_probe(struct usb_serial_port *port) + { +- struct usb_serial_port *port = serial->port[0]; + struct oti6858_private *priv; +- int i; + +- for (i = 0; i < serial->num_ports; ++i) { +- priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL); +- if (!priv) +- break; +- +- spin_lock_init(&priv->lock); +- init_waitqueue_head(&priv->intr_wait); +-/* INIT_WORK(&priv->setup_work, setup_line, serial->port[i]); */ +-/* INIT_WORK(&priv->write_work, send_data, serial->port[i]); */ +- priv->port = port; +- INIT_DELAYED_WORK(&priv->delayed_setup_work, setup_line); +- INIT_DELAYED_WORK(&priv->delayed_write_work, send_data); +- +- usb_set_serial_port_data(serial->port[i], priv); +- } +- if (i == serial->num_ports) +- return 0; +- +- 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; ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ spin_lock_init(&priv->lock); ++ init_waitqueue_head(&priv->intr_wait); ++ priv->port = port; ++ INIT_DELAYED_WORK(&priv->delayed_setup_work, setup_line); ++ INIT_DELAYED_WORK(&priv->delayed_write_work, send_data); ++ ++ usb_set_serial_port_data(port, priv); ++ ++ return 0; ++} ++ ++static int oti6858_port_remove(struct usb_serial_port *port) ++{ ++ struct oti6858_private *priv; ++ ++ priv = usb_get_serial_port_data(port); ++ kfree(priv); ++ ++ return 0; + } + + static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, +@@ -714,15 +711,6 @@ static int oti6858_ioctl(struct tty_stru + return -ENOIOCTLCMD; + } + +- +-static void oti6858_release(struct usb_serial *serial) +-{ +- int i; +- +- for (i = 0; i < serial->num_ports; ++i) +- kfree(usb_get_serial_port_data(serial->port[i])); +-} +- + static void oti6858_read_int_callback(struct urb *urb) + { + struct usb_serial_port *port = urb->context; diff --git a/queue-3.6/usb-pl2303-fix-port-data-memory-leak.patch b/queue-3.6/usb-pl2303-fix-port-data-memory-leak.patch new file mode 100644 index 00000000000..4f0355878e9 --- /dev/null +++ b/queue-3.6/usb-pl2303-fix-port-data-memory-leak.patch @@ -0,0 +1,199 @@ +From 8bf769eb5f6efc33f95088850f33fcc05d28b508 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 15 Oct 2012 15:47:21 +0200 +Subject: USB: pl2303: fix port-data memory leak + +From: Johan Hovold + +commit 8bf769eb5f6efc33f95088850f33fcc05d28b508 upstream. + +Fix port-data memory leak by allocating and freeing port data in +port_probe/remove rather than in attach/release, and by introducing +serial private data to store the device type which is interface rather +than port specific. + +Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no +driver is bound) the port private data is no longer freed at release. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/pl2303.c | 90 ++++++++++++++++++++++++++------------------ + 1 file changed, 54 insertions(+), 36 deletions(-) + +--- a/drivers/usb/serial/pl2303.c ++++ b/drivers/usb/serial/pl2303.c +@@ -135,12 +135,15 @@ enum pl2303_type { + HX, /* HX version of the pl2303 chip */ + }; + ++struct pl2303_serial_private { ++ enum pl2303_type type; ++}; ++ + struct pl2303_private { + spinlock_t lock; + wait_queue_head_t delta_msr_wait; + u8 line_control; + u8 line_status; +- enum pl2303_type type; + }; + + static int pl2303_vendor_read(__u16 value, __u16 index, +@@ -169,14 +172,19 @@ static int pl2303_vendor_write(__u16 val + + static int pl2303_startup(struct usb_serial *serial) + { +- struct pl2303_private *priv; ++ struct pl2303_serial_private *spriv; + enum pl2303_type type = type_0; + unsigned char *buf; +- int i; ++ ++ spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); ++ if (!spriv) ++ return -ENOMEM; + + buf = kmalloc(10, GFP_KERNEL); +- if (buf == NULL) ++ if (!buf) { ++ kfree(spriv); + return -ENOMEM; ++ } + + if (serial->dev->descriptor.bDeviceClass == 0x02) + type = type_0; +@@ -188,15 +196,8 @@ static int pl2303_startup(struct usb_ser + type = type_1; + dev_dbg(&serial->interface->dev, "device type: %d\n", type); + +- for (i = 0; i < serial->num_ports; ++i) { +- priv = kzalloc(sizeof(struct pl2303_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); +- } ++ spriv->type = type; ++ usb_set_serial_data(serial, spriv); + + pl2303_vendor_read(0x8484, 0, serial, buf); + pl2303_vendor_write(0x0404, 0, serial); +@@ -215,15 +216,40 @@ static int pl2303_startup(struct usb_ser + + kfree(buf); + return 0; ++} + +-cleanup: +- kfree(buf); +- 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; ++static void pl2303_release(struct usb_serial *serial) ++{ ++ struct pl2303_serial_private *spriv; ++ ++ spriv = usb_get_serial_data(serial); ++ kfree(spriv); ++} ++ ++static int pl2303_port_probe(struct usb_serial_port *port) ++{ ++ struct pl2303_private *priv; ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ spin_lock_init(&priv->lock); ++ init_waitqueue_head(&priv->delta_msr_wait); ++ ++ usb_set_serial_port_data(port, priv); ++ ++ return 0; ++} ++ ++static int pl2303_port_remove(struct usb_serial_port *port) ++{ ++ struct pl2303_private *priv; ++ ++ priv = usb_get_serial_port_data(port); ++ kfree(priv); ++ ++ return 0; + } + + static int set_control_lines(struct usb_device *dev, u8 value) +@@ -242,6 +268,7 @@ static void pl2303_set_termios(struct tt + struct usb_serial_port *port, struct ktermios *old_termios) + { + struct usb_serial *serial = port->serial; ++ struct pl2303_serial_private *spriv = usb_get_serial_data(serial); + struct pl2303_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + unsigned int cflag; +@@ -325,7 +352,7 @@ static void pl2303_set_termios(struct tt + } + if (baud > 1228800) { + /* type_0, type_1 only support up to 1228800 baud */ +- if (priv->type != HX) ++ if (spriv->type != HX) + baud = 1228800; + else if (baud > 6000000) + baud = 6000000; +@@ -428,7 +455,7 @@ static void pl2303_set_termios(struct tt + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + + if (cflag & CRTSCTS) { +- if (priv->type == HX) ++ if (spriv->type == HX) + pl2303_vendor_write(0x0, 0x61, serial); + else + pl2303_vendor_write(0x0, 0x41, serial); +@@ -470,10 +497,10 @@ static int pl2303_open(struct tty_struct + { + struct ktermios tmp_termios; + struct usb_serial *serial = port->serial; +- struct pl2303_private *priv = usb_get_serial_port_data(port); ++ struct pl2303_serial_private *spriv = usb_get_serial_data(serial); + int result; + +- if (priv->type != HX) { ++ if (spriv->type != HX) { + usb_clear_halt(serial->dev, port->write_urb->pipe); + usb_clear_halt(serial->dev, port->read_urb->pipe); + } else { +@@ -657,17 +684,6 @@ static void pl2303_break_ctl(struct tty_ + dev_err(&port->dev, "error sending break = %d\n", result); + } + +-static void pl2303_release(struct usb_serial *serial) +-{ +- int i; +- struct pl2303_private *priv; +- +- for (i = 0; i < serial->num_ports; ++i) { +- priv = usb_get_serial_port_data(serial->port[i]); +- kfree(priv); +- } +-} +- + static void pl2303_update_line_status(struct usb_serial_port *port, + unsigned char *data, + unsigned int actual_length) +@@ -829,6 +845,8 @@ static struct usb_serial_driver pl2303_d + .read_int_callback = pl2303_read_int_callback, + .attach = pl2303_startup, + .release = pl2303_release, ++ .port_probe = pl2303_port_probe, ++ .port_remove = pl2303_port_remove, + }; + + static struct usb_serial_driver * const serial_drivers[] = { diff --git a/queue-3.6/usb-ssu100-fix-port-data-memory-leak.patch b/queue-3.6/usb-ssu100-fix-port-data-memory-leak.patch new file mode 100644 index 00000000000..981116399d5 --- /dev/null +++ b/queue-3.6/usb-ssu100-fix-port-data-memory-leak.patch @@ -0,0 +1,91 @@ +From 638b9e15233c9570bce65301aa9877235316b9f0 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 17 Oct 2012 16:31:34 +0200 +Subject: USB: ssu100: fix port-data memory leak + +From: Johan Hovold + +commit 638b9e15233c9570bce65301aa9877235316b9f0 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/ssu100.c | 34 ++++++++++++++++++++-------------- + 1 file changed, 20 insertions(+), 14 deletions(-) + +--- a/drivers/usb/serial/ssu100.c ++++ b/drivers/usb/serial/ssu100.c +@@ -69,13 +69,6 @@ struct ssu100_port_private { + struct async_icount icount; + }; + +-static void ssu100_release(struct usb_serial *serial) +-{ +- struct ssu100_port_private *priv = usb_get_serial_port_data(*serial->port); +- +- kfree(priv); +-} +- + static inline int ssu100_control_msg(struct usb_device *dev, + u8 request, u16 data, u16 index) + { +@@ -444,21 +437,33 @@ static int ssu100_ioctl(struct tty_struc + + static int ssu100_attach(struct usb_serial *serial) + { ++ return ssu100_initdevice(serial->dev); ++} ++ ++static int ssu100_port_probe(struct usb_serial_port *port) ++{ + struct ssu100_port_private *priv; +- struct usb_serial_port *port = *serial->port; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); +- if (!priv) { +- dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__, +- sizeof(*priv)); ++ if (!priv) + return -ENOMEM; +- } + + spin_lock_init(&priv->status_lock); + init_waitqueue_head(&priv->delta_msr_wait); ++ + usb_set_serial_port_data(port, priv); + +- return ssu100_initdevice(serial->dev); ++ return 0; ++} ++ ++static int ssu100_port_remove(struct usb_serial_port *port) ++{ ++ struct ssu100_port_private *priv; ++ ++ priv = usb_get_serial_port_data(port); ++ kfree(priv); ++ ++ return 0; + } + + static int ssu100_tiocmget(struct tty_struct *tty) +@@ -649,7 +654,8 @@ static struct usb_serial_driver ssu100_d + .open = ssu100_open, + .close = ssu100_close, + .attach = ssu100_attach, +- .release = ssu100_release, ++ .port_probe = ssu100_port_probe, ++ .port_remove = ssu100_port_remove, + .dtr_rts = ssu100_dtr_rts, + .process_read_urb = ssu100_process_read_urb, + .tiocmget = ssu100_tiocmget,