On Thu, May 06, 2004 at 08:15:15PM +1000, herbert wrote:
> 
> 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.

I've updated the patch for 2.6.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.13
diff -u -r1.1.1.13 hiddev.c
--- a/drivers/usb/input/hiddev.c        10 May 2004 09:48:01 -0000      1.1.1.13
+++ b/drivers/usb/input/hiddev.c        10 May 2004 22:07:48 -0000
@@ -573,38 +573,11 @@
 
                return 0;
 
-       case HIDIOCGUCODE:
-               uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), 
GFP_KERNEL);
-               if (!uref_multi)
-                       return -ENOMEM;
-               uref = &uref_multi->uref;
-               if (copy_from_user(uref, (void *) arg, sizeof(*uref))) 
-                       goto fault;
-
-               rinfo.report_type = uref->report_type;
-               rinfo.report_id = uref->report_id;
-               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                       goto inval;
-
-               if (uref->field_index >= report->maxfield)
-                       goto inval;
-
-               field = report->field[uref->field_index];
-               if (uref->usage_index >= field->maxusage)
-                       goto inval;
-
-               uref->usage_code = field->usage[uref->usage_index].hid;
-
-               if (copy_to_user((void *) arg, uref, sizeof(*uref)))
-                       goto fault;
-
-               kfree(uref_multi);
-               return 0;
-
        case HIDIOCGUSAGE:
        case HIDIOCSUSAGE:
        case HIDIOCGUSAGES:
        case HIDIOCSUSAGES:
+       case HIDIOCGUCODE:
        case HIDIOCGCOLLECTIONINDEX:
                uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), 
GFP_KERNEL);
                if (!uref_multi)
@@ -621,10 +594,12 @@
 
                if (cmd != HIDIOCGUSAGE && 
                    cmd != HIDIOCGUSAGES &&
+                   cmd != HIDIOCGUCODE &&
                    uref->report_type == HID_REPORT_TYPE_INPUT)
                        goto inval;
 
-               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)
                                goto inval;
@@ -638,28 +613,34 @@
                                goto inval;
 
                        field = report->field[uref->field_index];
-                       if (uref->usage_index >= field->maxusage)
-                               goto inval;
-
-                       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)
                                        goto inval;
-                       }
+                       } else if (uref->usage_index >= field->report_count)
+                               goto inval;
+                       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))
+                               goto inval;
                }
 
                switch (cmd) {
                        case HIDIOCGUSAGE:
                                uref->value = field->value[uref->usage_index];
-                               if (copy_to_user((void *) arg, uref, sizeof(*uref)))
-                                       goto fault;
-                               goto goodreturn;
+                               break;
 
                        case HIDIOCSUSAGE:
                                field->value[uref->usage_index] = uref->value;
                                goto goodreturn;
 
+                       case HIDIOCGUCODE:
+                               uref->usage_code = field->usage[uref->usage_index].hid;
+                               break;
+
                        case HIDIOCGCOLLECTIONINDEX:
                                kfree(uref_multi);
                                return 
field->usage[uref->usage_index].collection_index;
@@ -678,6 +659,8 @@
                                goto goodreturn;
                }
 
+               if (copy_to_user((void *) arg, uref, sizeof(*uref)))
+                       goto fault;
 goodreturn:
                kfree(uref_multi);
                return 0;

Reply via email to