ChangeSet 1.911, 2002/11/20 00:10:26-08:00, zwane@holomorphy.com

[PATCH] USB core/config.c == memory corruption

parse_interface allocates the incorrect storage size for additional
altsettings (new buffer) leading to a BUG being triggered in
mm/slab.c:1453 when we do the memcpy from the old buffer to the new
buffer (writing beyond new buffer).
Patch appended, tested with an OV511 on an Intel PIIX4


diff -Nru a/drivers/usb/core/config.c b/drivers/usb/core/config.c
--- a/drivers/usb/core/config.c	Wed Nov 20 01:00:47 2002
+++ b/drivers/usb/core/config.c	Wed Nov 20 01:00:47 2002
@@ -109,7 +109,8 @@
 	interface->num_altsetting = 0;
 	interface->max_altsetting = USB_ALTSETTINGALLOC;
 
-	interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * interface->max_altsetting, GFP_KERNEL);
+	interface->altsetting = kmalloc(sizeof(*interface->altsetting) * interface->max_altsetting,
+					GFP_KERNEL);
 	
 	if (!interface->altsetting) {
 		err("couldn't kmalloc interface->altsetting");
@@ -118,29 +119,27 @@
 
 	while (size > 0) {
 		struct usb_interface_descriptor	*d;
-
+	
 		if (interface->num_altsetting >= interface->max_altsetting) {
-			void *ptr;
+			struct usb_host_interface *ptr;
 			int oldmas;
 
 			oldmas = interface->max_altsetting;
 			interface->max_altsetting += USB_ALTSETTINGALLOC;
 			if (interface->max_altsetting > USB_MAXALTSETTING) {
-				warn("too many alternate settings (max %d)",
-					USB_MAXALTSETTING);
+				warn("too many alternate settings (incr %d max %d)\n",
+					USB_ALTSETTINGALLOC, USB_MAXALTSETTING);
 				return -1;
 			}
 
-			ptr = interface->altsetting;
-			interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * interface->max_altsetting, GFP_KERNEL);
-			if (!interface->altsetting) {
+			ptr = kmalloc(sizeof(*ptr) * interface->max_altsetting, GFP_KERNEL);
+			if (ptr == NULL) {
 				err("couldn't kmalloc interface->altsetting");
-				interface->altsetting = ptr;
 				return -1;
 			}
-			memcpy(interface->altsetting, ptr, sizeof(struct usb_interface_descriptor) * oldmas);
-
-			kfree(ptr);
+			memcpy(ptr, interface->altsetting, sizeof(*interface->altsetting) * oldmas);
+			kfree(interface->altsetting);
+			interface->altsetting = ptr;
 		}
 
 		ifp = interface->altsetting + interface->num_altsetting;
