diff options
author | Jiri Kosina <jkosina@suse.cz> | 2012-04-26 18:56:08 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2012-04-27 14:10:09 -0400 |
commit | b6787242f32700377d3da3b8d788ab3928bab849 (patch) | |
tree | 54428bcff5865df64980d0af4423d52b6c1dffa5 /drivers/hid | |
parent | d4f0e4daf0d867f80c78ca4f9ac03a562e229e72 (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.c | 16 | ||||
-rw-r--r-- | drivers/hid/hidraw.c | 19 |
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 | ||
1035 | void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, | 1035 | int 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); |
1078 | out: | ||
1079 | return ret; | ||
1074 | } | 1080 | } |
1075 | EXPORT_SYMBOL_GPL(hid_report_raw_event); | 1081 | EXPORT_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 | ||
1152 | unlock: | 1158 | unlock: |
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 | ||
440 | void hidraw_report_event(struct hid_device *hid, u8 *data, int len) | 442 | int 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 | } |
454 | EXPORT_SYMBOL_GPL(hidraw_report_event); | 461 | EXPORT_SYMBOL_GPL(hidraw_report_event); |
455 | 462 | ||