Hi:

The current code is applying the maxusage limit to GUSAGE/SUSAGE.  This
is incorrect as the number of values is stored in field->report_count,
not field->maxusage.  The USB phone from www.virbiage.com is one device
where report_count exceeds maxusage.

The following patch corrects the check for 2.6.

Cheers,
-- 
Debian GNU/Linux 3.0 is out! ( http://www.debian.org/ )
Email:  Herbert Xu ~{PmV>HI~} <[EMAIL PROTECTED]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Index: drivers/usb/input/hiddev.c
===================================================================
RCS file: 
/home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/drivers/usb/input/hiddev.c,v
retrieving revision 1.1.1.12
diff -u -r1.1.1.12 hiddev.c
--- a/drivers/usb/input/hiddev.c        5 Apr 2004 09:49:36 -0000       1.1.1.12
+++ b/drivers/usb/input/hiddev.c        14 Apr 2004 10:07:25 -0000
@@ -575,33 +575,11 @@
 
                return 0;
 
-       case HIDIOCGUCODE:
-               if (copy_from_user(uref, (void *) arg, sizeof(*uref)))
-                       return -EFAULT;
-
-               rinfo.report_type = uref->report_type;
-               rinfo.report_id = uref->report_id;
-               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                       return -EINVAL;
-
-               if (uref->field_index >= report->maxfield)
-                       return -EINVAL;
-
-               field = report->field[uref->field_index];
-               if (uref->usage_index >= field->maxusage)
-                       return -EINVAL;
-
-               uref->usage_code = field->usage[uref->usage_index].hid;
-
-               if (copy_to_user((void *) arg, uref, sizeof(*uref)))
-                       return -EFAULT;
-
-               return 0;
-
        case HIDIOCGUSAGE:
        case HIDIOCSUSAGE:
        case HIDIOCGUSAGES:
        case HIDIOCSUSAGES:
+       case HIDIOCGUCODE:
        case HIDIOCGCOLLECTIONINDEX:
                if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
                        if (copy_from_user(&uref_multi, (void *) arg, 
@@ -617,7 +595,8 @@
                    uref->report_type == HID_REPORT_TYPE_INPUT)
                        return -EINVAL;
 
-               if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
+               if (cmd != HIDIOCGUCODE &&
+                   uref->report_id == HID_REPORT_ID_UNKNOWN) {
                        field = hiddev_lookup_usage(hid, uref);
                        if (field == NULL)
                                return -EINVAL;
@@ -631,28 +610,34 @@
                                return -EINVAL;
 
                        field = report->field[uref->field_index];
-                       if (uref->usage_index >= field->maxusage)
-                               return -EINVAL;
-
-                       if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
-                               if (uref_multi.num_values >= HID_MAX_USAGES || 
-                                   uref->usage_index >= field->maxusage || 
-                                  (uref->usage_index + uref_multi.num_values) >= 
field->maxusage)
+                       if (cmd == HIDIOCGUCODE ||
+                           cmd == HIDIOCGCOLLECTIONINDEX) {
+                               if (uref->usage_index >= field->maxusage)
                                        return -EINVAL;
-                       }
+                       } else if (uref->usage_index >= field->report_count)
+                               return -EINVAL;
+                       else if ((cmd == HIDIOCGUSAGES ||
+                                 cmd == HIDIOCSUSAGES) &&
+                                (uref->usage_index + uref_multi.num_values >=
+                                 field->report_count ||
+                                 uref->usage_index + uref_multi.num_values <
+                                 uref->usage_index))
+                               return -EINVAL;
                }
 
                switch (cmd) {
                        case HIDIOCGUSAGE:
                                uref->value = field->value[uref->usage_index];
-                               if (copy_to_user((void *) arg, uref, sizeof(*uref)))
-                                       return -EFAULT;
-                               return 0;
+                               break;
 
                        case HIDIOCSUSAGE:
                                field->value[uref->usage_index] = uref->value;
                                return 0;
 
+                       case HIDIOCGUCODE:
+                               uref->usage_code = field->usage[uref->usage_index].hid;
+                               break;
+
                        case HIDIOCGCOLLECTIONINDEX:
                                return 
field->usage[uref->usage_index].collection_index;
                        case HIDIOCGUSAGES:
@@ -670,6 +655,8 @@
                                return 0;
                }
 
+               if (copy_to_user((void *) arg, uref, sizeof(*uref)))
+                       return -EFAULT;
                return 0;
 
        case HIDIOCGCOLLECTIONINFO:

Reply via email to