On Fri, Jul 09, 2004 at 04:34:24PM +0400, Sergey Vlasov wrote: > On Thu, Jul 08, 2004 at 10:39:24PM -0700, Pete Zaitcev wrote: > > On Wed, 7 Jul 2004 17:52:01 -0400 > > Adam Kropelin <[EMAIL PROTECTED]> wrote: > > > > > /* hiddev_usage_ref_multi is used for sending multiple bytes to a control. > > > * It really manifests itself as setting the value of consecutive usages */ > > > +#define HID_MAX_MULTI_USAGES 1024 > > > struct hiddev_usage_ref_multi { > > > struct hiddev_usage_ref uref; > > > __u32 num_values; > > > - __s32 values[HID_MAX_USAGES]; > > > + __s32 values[HID_MAX_MULTI_USAGES]; > > > }; > > > > Woa dude, this is some enormous struct here. I sure hope we do not > > leave it included into some other struct accidentially. > > It is even worse - this monster thing is allocated on the kernel stack in > hiddev_ioctl() :(
Ewwww. Somebody botched that up but good. Here is a patch to fix up hiddev_ioctl(), slightly improved over the way it was done for 2.6. This patch avoids allocating a uref_multi when a standard uref will do. It also fixes copy_{to,from}_user() return value handling as was done in 2.6. --Adam --- linux-2.4.26/drivers/usb/hiddev.c.orig Fri Jul 9 14:54:17 2004 +++ linux-2.4.26/drivers/usb/hiddev.c Fri Jul 9 15:06:01 2004 @@ -396,8 +396,8 @@ struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; - struct hiddev_usage_ref_multi uref_multi; - struct hiddev_usage_ref *uref = &uref_multi.uref; + struct hiddev_usage_ref_multi *uref_multi; + struct hiddev_usage_ref *uref; struct hiddev_devinfo dinfo; struct hid_report *report; struct hid_field *field; @@ -555,96 +555,126 @@ return copy_to_user((void *) arg, &finfo, sizeof(finfo)); case HIDIOCGUCODE: + uref = kmalloc(sizeof(*uref), GFP_KERNEL); + if (!uref) + return -ENOMEM; if (copy_from_user(uref, (void *) arg, sizeof(*uref))) - return -EFAULT; + goto uref_fault; rinfo.report_type = uref->report_type; rinfo.report_id = uref->report_id; if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; + goto uref_inval; if (uref->field_index >= report->maxfield) - return -EINVAL; + goto uref_inval; field = report->field[uref->field_index]; if (uref->usage_index >= field->maxusage) - return -EINVAL; + goto uref_inval; uref->usage_code = field->usage[uref->usage_index].hid; - return copy_to_user((void *) arg, uref, sizeof(*uref)); + if (copy_to_user((void *) arg, uref, sizeof(*uref))) + goto uref_fault; + + kfree(uref); + return 0; +uref_fault: + kfree(uref); + return -EFAULT; +uref_inval: + kfree(uref); + return -EINVAL; case HIDIOCGUSAGE: case HIDIOCSUSAGE: case HIDIOCGUSAGES: case HIDIOCSUSAGES: case HIDIOCGCOLLECTIONINDEX: + uref_multi = kmalloc(sizeof(*uref_multi), GFP_KERNEL); + if (!uref_multi) + return -ENOMEM; + uref = &uref_multi->uref; if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { - if (copy_from_user(&uref_multi, (void *) arg, - sizeof(uref_multi))) - return -EFAULT; + if (copy_from_user(uref_multi, (void *) arg, + sizeof(*uref_multi))) + goto fault; } else { if (copy_from_user(uref, (void *) arg, sizeof(*uref))) - return -EFAULT; + goto fault; } if (cmd != HIDIOCGUSAGE && cmd != HIDIOCGUSAGES && uref->report_type == HID_REPORT_TYPE_INPUT) - return -EINVAL; + goto inval; if (uref->report_id == HID_REPORT_ID_UNKNOWN) { field = hiddev_lookup_usage(hid, uref); if (field == NULL) - return -EINVAL; + goto inval; } else { rinfo.report_type = uref->report_type; rinfo.report_id = uref->report_id; if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; + goto inval; if (uref->field_index >= report->maxfield) - return -EINVAL; + goto inval; field = report->field[uref->field_index]; if (uref->usage_index >= field->maxusage) - return -EINVAL; + goto inval; if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { - if (uref_multi.num_values >= HID_MAX_USAGES || + if (uref_multi->num_values >= HID_MAX_USAGES || uref->usage_index >= field->maxusage || - (uref->usage_index + uref_multi.num_values) >= field->maxusage) - return -EINVAL; + (uref->usage_index + uref_multi->num_values) >= field->maxusage) + goto inval; } } switch (cmd) { case HIDIOCGUSAGE: uref->value = field->value[uref->usage_index]; - return copy_to_user((void *) arg, uref, sizeof(*uref)); + if (copy_to_user((void *) arg, uref, sizeof(*uref))) + goto fault; + goto goodreturn; case HIDIOCSUSAGE: field->value[uref->usage_index] = uref->value; - return 0; + goto goodreturn; case HIDIOCGCOLLECTIONINDEX: + kfree(uref_multi); return field->usage[uref->usage_index].collection_index; case HIDIOCGUSAGES: - for (i = 0; i < uref_multi.num_values; i++) - uref_multi.values[i] = + for (i = 0; i < uref_multi->num_values; i++) + uref_multi->values[i] = field->value[uref->usage_index + i]; - if (copy_to_user((void *) arg, &uref_multi, - sizeof(uref_multi))) - return -EFAULT; - return 0; + if (copy_to_user((void *) arg, uref_multi, + sizeof(*uref_multi))) + goto fault; + goto goodreturn; case HIDIOCSUSAGES: - for (i = 0; i < uref_multi.num_values; i++) + for (i = 0; i < uref_multi->num_values; i++) field->value[uref->usage_index + i] = - uref_multi.values[i]; - return 0; + uref_multi->values[i]; + goto goodreturn; } break; +goodreturn: + kfree(uref_multi); + return 0; +fault: + kfree(uref_multi); + return -EFAULT; +inval: + kfree(uref_multi); + return -EINVAL; + case HIDIOCGCOLLECTIONINFO: if (copy_from_user(&cinfo, (void *) arg, sizeof(cinfo))) return -EFAULT; ------------------------------------------------------- This SF.Net email sponsored by Black Hat Briefings & Training. Attend Black Hat Briefings & Training, Las Vegas July 24-29 - digital self defense, top technical experts, no vendor pitches, unmatched networking opportunities. Visit www.blackhat.com _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel