[ 053/101] USB: whiteheat: fix port-data memory leak

From: Greg Kroah-Hartman
Date: Mon Oct 29 2012 - 18:09:08 EST


3.6-stable review patch. If anyone has any objections, please let me know.

------------------

From: Johan Hovold <jhovold@xxxxxxxxx>

commit c467206ed6bcce26c83d0435612cc4fee2527305 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.

Note that the fifth port (command port) is never registered as a
port device and thus should be handled in attach and release.

Compile-only tested.

Signed-off-by: Johan Hovold <jhovold@xxxxxxxxx>
Cc: <support@xxxxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
drivers/usb/serial/whiteheat.c | 59 ++++++++++++++++++-----------------------
1 file changed, 26 insertions(+), 33 deletions(-)

--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -86,6 +86,8 @@ static int whiteheat_firmware_attach(st
/* function prototypes for the Connect Tech WhiteHEAT serial converter */
static int whiteheat_attach(struct usb_serial *serial);
static void whiteheat_release(struct usb_serial *serial);
+static int whiteheat_port_probe(struct usb_serial_port *port);
+static int whiteheat_port_remove(struct usb_serial_port *port);
static int whiteheat_open(struct tty_struct *tty,
struct usb_serial_port *port);
static void whiteheat_close(struct usb_serial_port *port);
@@ -120,6 +122,8 @@ static struct usb_serial_driver whitehea
.num_ports = 4,
.attach = whiteheat_attach,
.release = whiteheat_release,
+ .port_probe = whiteheat_port_probe,
+ .port_remove = whiteheat_port_remove,
.open = whiteheat_open,
.close = whiteheat_close,
.ioctl = whiteheat_ioctl,
@@ -290,15 +294,12 @@ static int whiteheat_attach(struct usb_s
{
struct usb_serial_port *command_port;
struct whiteheat_command_private *command_info;
- struct usb_serial_port *port;
- struct whiteheat_private *info;
struct whiteheat_hw_info *hw_info;
int pipe;
int ret;
int alen;
__u8 *command;
__u8 *result;
- int i;

command_port = serial->port[COMMAND_PORT];

@@ -357,22 +358,6 @@ static int whiteheat_attach(struct usb_s
serial->type->description,
hw_info->sw_major_rev, hw_info->sw_minor_rev);

- for (i = 0; i < serial->num_ports; i++) {
- port = serial->port[i];
-
- info = kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL);
- if (info == NULL) {
- dev_err(&port->dev,
- "%s: Out of memory for port structures\n",
- serial->type->description);
- goto no_private;
- }
-
- info->mcr = 0;
-
- usb_set_serial_port_data(port, info);
- }
-
command_info = kmalloc(sizeof(struct whiteheat_command_private),
GFP_KERNEL);
if (command_info == NULL) {
@@ -409,13 +394,6 @@ no_firmware:
return -ENODEV;

no_command_private:
- for (i = serial->num_ports - 1; i >= 0; i--) {
- port = serial->port[i];
- info = usb_get_serial_port_data(port);
- kfree(info);
-no_private:
- ;
- }
kfree(result);
no_result_buffer:
kfree(command);
@@ -423,21 +401,36 @@ no_command_buffer:
return -ENOMEM;
}

-
static void whiteheat_release(struct usb_serial *serial)
{
struct usb_serial_port *command_port;
- struct whiteheat_private *info;
- int i;

/* free up our private data for our command port */
command_port = serial->port[COMMAND_PORT];
kfree(usb_get_serial_port_data(command_port));
+}

- for (i = 0; i < serial->num_ports; i++) {
- info = usb_get_serial_port_data(serial->port[i]);
- kfree(info);
- }
+static int whiteheat_port_probe(struct usb_serial_port *port)
+{
+ struct whiteheat_private *info;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ usb_set_serial_port_data(port, info);
+
+ return 0;
+}
+
+static int whiteheat_port_remove(struct usb_serial_port *port)
+{
+ struct whiteheat_private *info;
+
+ info = usb_get_serial_port_data(port);
+ kfree(info);
+
+ return 0;
}

static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/