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;