On Wed, Apr 14, 2004 at 08:22:17PM +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.
And here is the corresponding patch for 2.4. -- 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/hiddev.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.4/drivers/usb/hiddev.c,v retrieving revision 1.1.1.3 retrieving revision 1.2 diff -u -r1.1.1.3 -r1.2 --- a/drivers/usb/hiddev.c 30 Aug 2003 06:01:42 -0000 1.1.1.3 +++ b/drivers/usb/hiddev.c 14 Apr 2004 09:30:15 -0000 1.2 @@ -553,28 +553,9 @@ return copy_to_user((void *) arg, &finfo, sizeof(finfo)); - 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; - - return copy_to_user((void *) arg, &uref, sizeof(uref)); - case HIDIOCGUSAGE: case HIDIOCSUSAGE: + case HIDIOCGUCODE: case HIDIOCGCOLLECTIONINDEX: if (copy_from_user(&uref, (void *) arg, sizeof(uref))) return -EFAULT; @@ -583,7 +564,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; @@ -597,23 +579,29 @@ return -EINVAL; field = report->field[uref.field_index]; - if (uref.usage_index >= field->maxusage) - return -EINVAL; + if (cmd == HIDIOCGUCODE || + cmd == HIDIOCGCOLLECTIONINDEX) { + if (uref.usage_index >= field->maxusage) + return -EINVAL; + } else { + if (uref.usage_index >= field->report_count) + return -EINVAL; + } } - switch (cmd) { - case HIDIOCGUSAGE: + if (cmd == HIDIOCGUCODE) + uref.usage_code = field->usage[uref.usage_index].hid; + else if (cmd == HIDIOCGUSAGE) uref.value = field->value[uref.usage_index]; - return copy_to_user((void *) arg, &uref, sizeof(uref)); - - case HIDIOCSUSAGE: + else if (cmd == HIDIOCSUSAGE) { field->value[uref.usage_index] = uref.value; return 0; - - case HIDIOCGCOLLECTIONINDEX: + } else { + /* cmd == HIDIOCGCOLLECTIONINDEX */ return field->usage[uref.usage_index].collection_index; } - break; + + return copy_to_user((void *) arg, &uref, sizeof(uref)); case HIDIOCGCOLLECTIONINFO: if (copy_from_user(&cinfo, (void *) arg, sizeof(cinfo)))