Vulnerability: The aiptek_probe function in drivers/input/tablet/aiptek.c in the Linux kernel before 4.4 allows physically proximate attackers to cause a denial of service (NULL pointer dereference and system crash) via a crafted USB device that lacks endpoints.
Vulnerability ID: CVE-2015-7515
CWE: CWE-476
Severity score: 6.9
Project: https://github.com/torvalds/linux
Published: 2016-04-27
File: drivers/input/tablet/aiptek.c
Commit message: Input: aiptek - fix crash on detecting device without endpoints

The aiptek driver crashes in aiptek_probe() when a specially crafted USB
device without endpoints is detected. This fix adds a check that the device
has proper configuration expected by the driver. Also an error return value
is changed to more matching one in one of the error paths.

Reported-by: Ralf Spenneberg <ralf@spenneberg.net>
Signed-off-by: Vladis Dronov <vdronov@redhat.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Commit author: Vladis Dronov

Vulnerable version (before fix):
 aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) 	input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); 	input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0);  	endpoint = &intf->altsetting[0].endpoint[0].desc;  	/* Go set up our URB, which is called when the tablet receives aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) 	if (i == ARRAY_SIZE(speeds)) { 		dev_info(&intf->dev, 			 "Aiptek tried all speeds, no sane response\n"); 		goto fail3; 	} 

Fixed version (after fix):
 aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) 	input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); 	input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0);  	/* Verify that a device really has an endpoint */ 	if (intf->altsetting[0].desc.bNumEndpoints < 1) { 		dev_err(&intf->dev, 			"interface has %d endpoints, but must have minimum 1\n", 			intf->altsetting[0].desc.bNumEndpoints); 		err = -EINVAL; 		goto fail3; 	} 	endpoint = &intf->altsetting[0].endpoint[0].desc;  	/* Go set up our URB, which is called when the tablet receives aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) 	if (i == ARRAY_SIZE(speeds)) { 		dev_info(&intf->dev, 			 "Aiptek tried all speeds, no sane response\n"); 		err = -EINVAL; 		goto fail3; 	} 

Patch:
patch: @@ -1819,6 +1819,14 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
 	input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0);
 
+	/* Verify that a device really has an endpoint */
+	if (intf->altsetting[0].desc.bNumEndpoints < 1) {
+		dev_err(&intf->dev,
+			"interface has %d endpoints, but must have minimum 1\n",
+			intf->altsetting[0].desc.bNumEndpoints);
+		err = -EINVAL;
+		goto fail3;
+	}
 	endpoint = &intf->altsetting[0].endpoint[0].desc;
 
 	/* Go set up our URB, which is called when the tablet receives
@@ -1861,6 +1869,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	if (i == ARRAY_SIZE(speeds)) {
 		dev_info(&intf->dev,
 			 "Aiptek tried all speeds, no sane response\n");
+		err = -EINVAL;
 		goto fail3;
 	}
path: drivers/input/tablet/aiptek.c