Commit 0e80d432 authored by Arjan van de Ven's avatar Arjan van de Ven Committed by Greg Kroah-Hartman

[PATCH] USB: usb hiddev stack usage patch

Patch below fixes some obscenely high stack uage;
struct hiddev_usage_ref_multi is well over 4Kb in size so really doesn't
belong on the stack.
parent 6f4388bc
...@@ -403,8 +403,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -403,8 +403,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct hiddev_collection_info cinfo; struct hiddev_collection_info cinfo;
struct hiddev_report_info rinfo; struct hiddev_report_info rinfo;
struct hiddev_field_info finfo; struct hiddev_field_info finfo;
struct hiddev_usage_ref_multi uref_multi; struct hiddev_usage_ref_multi *uref_multi=NULL;
struct hiddev_usage_ref *uref = &uref_multi.uref; struct hiddev_usage_ref *uref;
struct hiddev_devinfo dinfo; struct hiddev_devinfo dinfo;
struct hid_report *report; struct hid_report *report;
struct hid_field *field; struct hid_field *field;
...@@ -576,26 +576,31 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -576,26 +576,31 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return 0; return 0;
case HIDIOCGUCODE: case HIDIOCGUCODE:
if (copy_from_user(uref, (void *) arg, sizeof(*uref))) uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
return -EFAULT; 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_type = uref->report_type;
rinfo.report_id = uref->report_id; rinfo.report_id = uref->report_id;
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
return -EINVAL; goto inval;
if (uref->field_index >= report->maxfield) if (uref->field_index >= report->maxfield)
return -EINVAL; goto inval;
field = report->field[uref->field_index]; field = report->field[uref->field_index];
if (uref->usage_index >= field->maxusage) if (uref->usage_index >= field->maxusage)
return -EINVAL; goto inval;
uref->usage_code = field->usage[uref->usage_index].hid; uref->usage_code = field->usage[uref->usage_index].hid;
if (copy_to_user((void *) arg, uref, sizeof(*uref))) if (copy_to_user((void *) arg, uref, sizeof(*uref)))
return -EFAULT; goto fault;
kfree(uref_multi);
return 0; return 0;
case HIDIOCGUSAGE: case HIDIOCGUSAGE:
...@@ -603,42 +608,46 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -603,42 +608,46 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
case HIDIOCGUSAGES: case HIDIOCGUSAGES:
case HIDIOCSUSAGES: case HIDIOCSUSAGES:
case HIDIOCGCOLLECTIONINDEX: case HIDIOCGCOLLECTIONINDEX:
uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
if (!uref_multi)
return -ENOMEM;
uref = &uref_multi->uref;
if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
if (copy_from_user(&uref_multi, (void *) arg, if (copy_from_user(uref_multi, (void *) arg,
sizeof(uref_multi))) sizeof(uref_multi)))
return -EFAULT; goto fault;
} else { } else {
if (copy_from_user(uref, (void *) arg, sizeof(*uref))) if (copy_from_user(uref, (void *) arg, sizeof(*uref)))
return -EFAULT; goto fault;
} }
if (cmd != HIDIOCGUSAGE && if (cmd != HIDIOCGUSAGE &&
cmd != HIDIOCGUSAGES && cmd != HIDIOCGUSAGES &&
uref->report_type == HID_REPORT_TYPE_INPUT) uref->report_type == HID_REPORT_TYPE_INPUT)
return -EINVAL; goto inval;
if (uref->report_id == HID_REPORT_ID_UNKNOWN) { if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
field = hiddev_lookup_usage(hid, uref); field = hiddev_lookup_usage(hid, uref);
if (field == NULL) if (field == NULL)
return -EINVAL; goto inval;
} else { } else {
rinfo.report_type = uref->report_type; rinfo.report_type = uref->report_type;
rinfo.report_id = uref->report_id; rinfo.report_id = uref->report_id;
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
return -EINVAL; goto inval;
if (uref->field_index >= report->maxfield) if (uref->field_index >= report->maxfield)
return -EINVAL; goto inval;
field = report->field[uref->field_index]; field = report->field[uref->field_index];
if (uref->usage_index >= field->maxusage) if (uref->usage_index >= field->maxusage)
return -EINVAL; goto inval;
if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { 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 >= field->maxusage ||
(uref->usage_index + uref_multi.num_values) >= field->maxusage) (uref->usage_index + uref_multi->num_values) >= field->maxusage)
return -EINVAL; goto inval;
} }
} }
...@@ -646,31 +655,40 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -646,31 +655,40 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
case HIDIOCGUSAGE: case HIDIOCGUSAGE:
uref->value = field->value[uref->usage_index]; uref->value = field->value[uref->usage_index];
if (copy_to_user((void *) arg, uref, sizeof(*uref))) if (copy_to_user((void *) arg, uref, sizeof(*uref)))
return -EFAULT; goto fault;
return 0; goto goodreturn;
case HIDIOCSUSAGE: case HIDIOCSUSAGE:
field->value[uref->usage_index] = uref->value; field->value[uref->usage_index] = uref->value;
return 0; goto goodreturn;
case HIDIOCGCOLLECTIONINDEX: case HIDIOCGCOLLECTIONINDEX:
kfree(uref_multi);
return field->usage[uref->usage_index].collection_index; return field->usage[uref->usage_index].collection_index;
case HIDIOCGUSAGES: case HIDIOCGUSAGES:
for (i = 0; i < uref_multi.num_values; i++) for (i = 0; i < uref_multi->num_values; i++)
uref_multi.values[i] = uref_multi->values[i] =
field->value[uref->usage_index + i]; field->value[uref->usage_index + i];
if (copy_to_user((void *) arg, &uref_multi, if (copy_to_user((void *) arg, uref_multi,
sizeof(uref_multi))) sizeof(*uref_multi)))
return -EFAULT; goto fault;
return 0; goto goodreturn;
case HIDIOCSUSAGES: 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] = field->value[uref->usage_index + i] =
uref_multi.values[i]; uref_multi->values[i];
return 0; goto goodreturn;
} }
goodreturn:
kfree(uref_multi);
return 0; return 0;
fault:
kfree(uref_multi);
return -EFAULT;
inval:
kfree(uref_multi);
return -EINVAL;
case HIDIOCGCOLLECTIONINFO: case HIDIOCGCOLLECTIONINFO:
if (copy_from_user(&cinfo, (void *) arg, sizeof(cinfo))) if (copy_from_user(&cinfo, (void *) arg, sizeof(cinfo)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment