48f65f6
From 10d98bced414c6fc1d09db123e7f762d91b5ebea Mon Sep 17 00:00:00 2001
48f65f6
From: Johan Hovold <johan@kernel.org>
48f65f6
Date: Wed, 23 Sep 2015 11:41:42 -0700
48f65f6
Subject: [PATCH] USB: whiteheat: fix potential null-deref at probe
48f65f6
48f65f6
Fix potential null-pointer dereference at probe by making sure that the
48f65f6
required endpoints are present.
48f65f6
48f65f6
The whiteheat driver assumes there are at least five pairs of bulk
48f65f6
endpoints, of which the final pair is used for the "command port". An
48f65f6
attempt to bind to an interface with fewer bulk endpoints would
48f65f6
currently lead to an oops.
48f65f6
48f65f6
Fixes CVE-2015-5257.
48f65f6
48f65f6
Reported-by: Moein Ghasemzadeh <moein@istuary.com>
48f65f6
Cc: stable <stable@vger.kernel.org>
48f65f6
Signed-off-by: Johan Hovold <johan@kernel.org>
48f65f6
---
48f65f6
 drivers/usb/serial/whiteheat.c | 31 +++++++++++++++++++++++++++++++
48f65f6
 1 file changed, 31 insertions(+)
48f65f6
48f65f6
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
48f65f6
index 6c3734d2b45a..d3ea90bef84d 100644
48f65f6
--- a/drivers/usb/serial/whiteheat.c
48f65f6
+++ b/drivers/usb/serial/whiteheat.c
48f65f6
@@ -80,6 +80,8 @@ static int  whiteheat_firmware_download(struct usb_serial *serial,
48f65f6
 static int  whiteheat_firmware_attach(struct usb_serial *serial);
48f65f6
 
48f65f6
 /* function prototypes for the Connect Tech WhiteHEAT serial converter */
48f65f6
+static int whiteheat_probe(struct usb_serial *serial,
48f65f6
+				const struct usb_device_id *id);
48f65f6
 static int  whiteheat_attach(struct usb_serial *serial);
48f65f6
 static void whiteheat_release(struct usb_serial *serial);
48f65f6
 static int  whiteheat_port_probe(struct usb_serial_port *port);
48f65f6
@@ -116,6 +118,7 @@ static struct usb_serial_driver whiteheat_device = {
48f65f6
 	.description =		"Connect Tech - WhiteHEAT",
48f65f6
 	.id_table =		id_table_std,
48f65f6
 	.num_ports =		4,
48f65f6
+	.probe =		whiteheat_probe,
48f65f6
 	.attach =		whiteheat_attach,
48f65f6
 	.release =		whiteheat_release,
48f65f6
 	.port_probe =		whiteheat_port_probe,
48f65f6
@@ -217,6 +220,34 @@ static int whiteheat_firmware_attach(struct usb_serial *serial)
48f65f6
 /*****************************************************************************
48f65f6
  * Connect Tech's White Heat serial driver functions
48f65f6
  *****************************************************************************/
48f65f6
+
48f65f6
+static int whiteheat_probe(struct usb_serial *serial,
48f65f6
+				const struct usb_device_id *id)
48f65f6
+{
48f65f6
+	struct usb_host_interface *iface_desc;
48f65f6
+	struct usb_endpoint_descriptor *endpoint;
48f65f6
+	size_t num_bulk_in = 0;
48f65f6
+	size_t num_bulk_out = 0;
48f65f6
+	size_t min_num_bulk;
48f65f6
+	unsigned int i;
48f65f6
+
48f65f6
+	iface_desc = serial->interface->cur_altsetting;
48f65f6
+
48f65f6
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
48f65f6
+		endpoint = &iface_desc->endpoint[i].desc;
48f65f6
+		if (usb_endpoint_is_bulk_in(endpoint))
48f65f6
+			++num_bulk_in;
48f65f6
+		if (usb_endpoint_is_bulk_out(endpoint))
48f65f6
+			++num_bulk_out;
48f65f6
+	}
48f65f6
+
48f65f6
+	min_num_bulk = COMMAND_PORT + 1;
48f65f6
+	if (num_bulk_in < min_num_bulk || num_bulk_out < min_num_bulk)
48f65f6
+		return -ENODEV;
48f65f6
+
48f65f6
+	return 0;
48f65f6
+}
48f65f6
+
48f65f6
 static int whiteheat_attach(struct usb_serial *serial)
48f65f6
 {
48f65f6
 	struct usb_serial_port *command_port;
48f65f6
-- 
48f65f6
2.4.3
48f65f6