aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2012-04-26 18:56:08 -0400
committerJiri Kosina <jkosina@suse.cz>2012-04-27 14:10:09 -0400
commitb6787242f32700377d3da3b8d788ab3928bab849 (patch)
tree54428bcff5865df64980d0af4423d52b6c1dffa5 /drivers/hid
parentd4f0e4daf0d867f80c78ca4f9ac03a562e229e72 (diff)
HID: hidraw: add proper error handling to raw event reporting
If kmemdup() in hidraw_report_event() fails, we are not propagating this fact properly. Let hidraw_report_event() and hid_report_raw_event() return an error value to the caller. Reported-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-core.c16
-rw-r--r--drivers/hid/hidraw.c19
2 files changed, 24 insertions, 11 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 8be458b79b2c..0cddcaa3fe7f 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1032,7 +1032,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
1032 return report; 1032 return report;
1033} 1033}
1034 1034
1035void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, 1035int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
1036 int interrupt) 1036 int interrupt)
1037{ 1037{
1038 struct hid_report_enum *report_enum = hid->report_enum + type; 1038 struct hid_report_enum *report_enum = hid->report_enum + type;
@@ -1040,10 +1040,11 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
1040 unsigned int a; 1040 unsigned int a;
1041 int rsize, csize = size; 1041 int rsize, csize = size;
1042 u8 *cdata = data; 1042 u8 *cdata = data;
1043 int ret = 0;
1043 1044
1044 report = hid_get_report(report_enum, data); 1045 report = hid_get_report(report_enum, data);
1045 if (!report) 1046 if (!report)
1046 return; 1047 goto out;
1047 1048
1048 if (report_enum->numbered) { 1049 if (report_enum->numbered) {
1049 cdata++; 1050 cdata++;
@@ -1063,14 +1064,19 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
1063 1064
1064 if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event) 1065 if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
1065 hid->hiddev_report_event(hid, report); 1066 hid->hiddev_report_event(hid, report);
1066 if (hid->claimed & HID_CLAIMED_HIDRAW) 1067 if (hid->claimed & HID_CLAIMED_HIDRAW) {
1067 hidraw_report_event(hid, data, size); 1068 ret = hidraw_report_event(hid, data, size);
1069 if (ret)
1070 goto out;
1071 }
1068 1072
1069 for (a = 0; a < report->maxfield; a++) 1073 for (a = 0; a < report->maxfield; a++)
1070 hid_input_field(hid, report->field[a], cdata, interrupt); 1074 hid_input_field(hid, report->field[a], cdata, interrupt);
1071 1075
1072 if (hid->claimed & HID_CLAIMED_INPUT) 1076 if (hid->claimed & HID_CLAIMED_INPUT)
1073 hidinput_report_event(hid, report); 1077 hidinput_report_event(hid, report);
1078out:
1079 return ret;
1074} 1080}
1075EXPORT_SYMBOL_GPL(hid_report_raw_event); 1081EXPORT_SYMBOL_GPL(hid_report_raw_event);
1076 1082
@@ -1147,7 +1153,7 @@ nomem:
1147 } 1153 }
1148 } 1154 }
1149 1155
1150 hid_report_raw_event(hid, type, data, size, interrupt); 1156 ret = hid_report_raw_event(hid, type, data, size, interrupt);
1151 1157
1152unlock: 1158unlock:
1153 up(&hid->driver_lock); 1159 up(&hid->driver_lock);
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index cf7d6d58e79f..36fa77b40ffb 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -87,11 +87,13 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
87 len = list->buffer[list->tail].len > count ? 87 len = list->buffer[list->tail].len > count ?
88 count : list->buffer[list->tail].len; 88 count : list->buffer[list->tail].len;
89 89
90 if (copy_to_user(buffer, list->buffer[list->tail].value, len)) { 90 if (list->buffer[list->tail].value) {
91 ret = -EFAULT; 91 if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
92 goto out; 92 ret = -EFAULT;
93 goto out;
94 }
95 ret = len;
93 } 96 }
94 ret = len;
95 97
96 kfree(list->buffer[list->tail].value); 98 kfree(list->buffer[list->tail].value);
97 list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1); 99 list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
@@ -437,19 +439,24 @@ static const struct file_operations hidraw_ops = {
437 .llseek = noop_llseek, 439 .llseek = noop_llseek,
438}; 440};
439 441
440void hidraw_report_event(struct hid_device *hid, u8 *data, int len) 442int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
441{ 443{
442 struct hidraw *dev = hid->hidraw; 444 struct hidraw *dev = hid->hidraw;
443 struct hidraw_list *list; 445 struct hidraw_list *list;
446 int ret = 0;
444 447
445 list_for_each_entry(list, &dev->list, node) { 448 list_for_each_entry(list, &dev->list, node) {
446 list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC); 449 if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) {
450 ret = -ENOMEM;
451 break;
452 }
447 list->buffer[list->head].len = len; 453 list->buffer[list->head].len = len;
448 list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1); 454 list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
449 kill_fasync(&list->fasync, SIGIO, POLL_IN); 455 kill_fasync(&list->fasync, SIGIO, POLL_IN);
450 } 456 }
451 457
452 wake_up_interruptible(&dev->wait); 458 wake_up_interruptible(&dev->wait);
459 return ret;
453} 460}
454EXPORT_SYMBOL_GPL(hidraw_report_event); 461EXPORT_SYMBOL_GPL(hidraw_report_event);
455 462